mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2024-11-22 09:26:37 +03:00
Completely overhaul the documentation
This commit is contained in:
parent
10251f9782
commit
0a3d6106f0
77
readthedocs/basic/installation.rst
Normal file
77
readthedocs/basic/installation.rst
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
.. _installation:
|
||||||
|
|
||||||
|
============
|
||||||
|
Installation
|
||||||
|
============
|
||||||
|
|
||||||
|
Telethon is a Python library, which means you need to download and install
|
||||||
|
Python from https://www.python.org/downloads/ if you haven't already. Once
|
||||||
|
you have Python installed, run:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
pip3 install -U telethon --user
|
||||||
|
|
||||||
|
To install or upgrade the library to the latest version.
|
||||||
|
|
||||||
|
|
||||||
|
Installing Development Versions
|
||||||
|
===============================
|
||||||
|
|
||||||
|
If you want the *latest* unreleased changes,
|
||||||
|
you can run the following command instead:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
pip3 install -U https://github.com/LonamiWebs/Telethon/archive/master.zip --user
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The development version may have bugs and is not recommended for production
|
||||||
|
use. However, when you are `reporting a library bug`__, you should try if the
|
||||||
|
bug still occurs in this version.
|
||||||
|
|
||||||
|
.. __: https://github.com/LonamiWebs/Telethon/issues/
|
||||||
|
|
||||||
|
|
||||||
|
Verification
|
||||||
|
============
|
||||||
|
|
||||||
|
To verify that the library is installed correctly, run the following command:
|
||||||
|
|
||||||
|
.. code-block:: sh
|
||||||
|
|
||||||
|
python3 -c 'import telethon; print(telethon.__version__)'
|
||||||
|
|
||||||
|
The version number of the library should show in the output.
|
||||||
|
|
||||||
|
|
||||||
|
Optional Dependencies
|
||||||
|
=====================
|
||||||
|
|
||||||
|
If cryptg_ is installed, **the library will work a lot faster**, since
|
||||||
|
encryption and decryption will be made in C instead of Python. If your
|
||||||
|
code deals with a lot of updates or you are downloading/uploading a lot
|
||||||
|
of files, you will notice a considerable speed-up (from a hundred kilobytes
|
||||||
|
per second to several megabytes per second, if your connection allows it).
|
||||||
|
If it's not installed, pyaes_ will be used (which is pure Python, so it's
|
||||||
|
much slower).
|
||||||
|
|
||||||
|
If pillow_ is installed, large images will be automatically resized when
|
||||||
|
sending photos to prevent Telegram from failing with "invalid image".
|
||||||
|
Official clients also do this.
|
||||||
|
|
||||||
|
If aiohttp_ is installed, the library will be able to download
|
||||||
|
:tl:`WebDocument` media files (otherwise you will get an error).
|
||||||
|
|
||||||
|
If hachoir_ is installed, it will be used to extract metadata from files
|
||||||
|
when sending documents. Telegram uses this information to show the song's
|
||||||
|
performer, artist, title, duration, and for videos too (including size).
|
||||||
|
Otherwise, they will default to empty values, and you can set the attributes
|
||||||
|
manually.
|
||||||
|
|
||||||
|
.. _cryptg: https://github.com/Lonami/cryptg
|
||||||
|
.. _pyaes: https://github.com/ricmoo/pyaes
|
||||||
|
.. _pillow: https://python-pillow.org
|
||||||
|
.. _aiohttp: https://docs.aiohttp.org
|
||||||
|
.. _hachoir: https://hachoir.readthedocs.io
|
22
readthedocs/basic/next-steps.rst
Normal file
22
readthedocs/basic/next-steps.rst
Normal file
|
@ -0,0 +1,22 @@
|
||||||
|
==========
|
||||||
|
Next Steps
|
||||||
|
==========
|
||||||
|
|
||||||
|
These basic first steps should have gotten you started with the library.
|
||||||
|
|
||||||
|
By now, you should know how to call friendly methods and how to work with
|
||||||
|
the returned objects, how things work inside event handlers, etc.
|
||||||
|
|
||||||
|
Next, we will see a quick reference summary of *all* the methods and
|
||||||
|
properties that you will need when using the library. If you follow
|
||||||
|
the links there, you will expand the documentation for the method
|
||||||
|
and property, with more examples on how to use them.
|
||||||
|
|
||||||
|
Therefore, **you can find an example on every method** of the client
|
||||||
|
to learn how to use it, as well as a description of all the arguments.
|
||||||
|
|
||||||
|
After that, we will go in-depth with some other important concepts
|
||||||
|
that are worth learning and understanding.
|
||||||
|
|
||||||
|
From now on, you can keep pressing the "Next" button if you want,
|
||||||
|
or use the menu on the left, since some pages are quite lengthy.
|
79
readthedocs/basic/quick-start.rst
Normal file
79
readthedocs/basic/quick-start.rst
Normal file
|
@ -0,0 +1,79 @@
|
||||||
|
===========
|
||||||
|
Quick-Start
|
||||||
|
===========
|
||||||
|
|
||||||
|
Let's see a longer example to learn some of the methods that the library
|
||||||
|
has to offer. These are known as "friendly methods", and you should always
|
||||||
|
use these if possible.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.sync import TelegramClient
|
||||||
|
|
||||||
|
# Remember to use your own values from my.telegram.org!
|
||||||
|
api_id = 12345
|
||||||
|
api_hash = '0123456789abcdef0123456789abcdef'
|
||||||
|
|
||||||
|
with TelegramClient('anon', api_id, api_hash) as client:
|
||||||
|
# Getting information about yourself
|
||||||
|
me = client.get_me()
|
||||||
|
|
||||||
|
# "me" is an User object. You can pretty-print
|
||||||
|
# any Telegram object with the "stringify" method:
|
||||||
|
print(me.stringify())
|
||||||
|
|
||||||
|
# When you print something, you see a representation of it.
|
||||||
|
# You can access all attributes of Telegram objects with
|
||||||
|
# the dot operator. For example, to get the username:
|
||||||
|
username = me.username
|
||||||
|
print(username)
|
||||||
|
print(me.phone)
|
||||||
|
|
||||||
|
# You can print all the dialogs/conversations that you are part of:
|
||||||
|
for dialog in client.iter_dialogs():
|
||||||
|
print(dialog.name, 'has ID', dialog.id)
|
||||||
|
|
||||||
|
# You can send messages to yourself...
|
||||||
|
client.send_message('me', 'Hello, myself!')
|
||||||
|
# ...to some chat ID
|
||||||
|
client.send_message(-100123456, 'Hello, group!')
|
||||||
|
# ...to your contacts
|
||||||
|
client.send_message('+34600123123', 'Hello, friend!')
|
||||||
|
# ...or even to any username
|
||||||
|
client.send_message('TelethonChat', 'Hello, Telethon!')
|
||||||
|
|
||||||
|
# You can, of course, use markdown in your messages:
|
||||||
|
message = client.send_message(
|
||||||
|
'me',
|
||||||
|
'This message has **bold**, `code`, __italics__ and '
|
||||||
|
'a [nice website](https://lonamiwebs.github.io)!',
|
||||||
|
link_preview=False
|
||||||
|
)
|
||||||
|
|
||||||
|
# Sending a message returns the sent message object, which you can use
|
||||||
|
print(message.raw_text)
|
||||||
|
|
||||||
|
# You can reply to messages directly if you have a message object
|
||||||
|
message.reply('Cool!')
|
||||||
|
|
||||||
|
# Or send files, songs, documents, albums...
|
||||||
|
client.send_file('me', '/home/me/Pictures/holidays.jpg')
|
||||||
|
|
||||||
|
# You can print the message history of any chat:
|
||||||
|
for message in client.iter_messages('me'):
|
||||||
|
print(message.id, message.text)
|
||||||
|
|
||||||
|
# You can download media from messages, too!
|
||||||
|
# The method will return the path where the file was saved.
|
||||||
|
if message.photo:
|
||||||
|
path = message.download_media()
|
||||||
|
print('File saved to', path)
|
||||||
|
|
||||||
|
|
||||||
|
Here, we show how to sign in, get information about yourself, send
|
||||||
|
messages, files, getting chats, printing messages, and downloading
|
||||||
|
files.
|
||||||
|
|
||||||
|
You should make sure that you understand what the code shown here
|
||||||
|
does, take note on how methods are called and used and so on before
|
||||||
|
proceeding. We will see all the available methods later on.
|
128
readthedocs/basic/signing-in.rst
Normal file
128
readthedocs/basic/signing-in.rst
Normal file
|
@ -0,0 +1,128 @@
|
||||||
|
.. _signing-in:
|
||||||
|
|
||||||
|
==========
|
||||||
|
Signing In
|
||||||
|
==========
|
||||||
|
|
||||||
|
Before working with Telegram's API, you need to get your own API ID and hash:
|
||||||
|
|
||||||
|
1. `Login to your Telegram account <https://my.telegram.org/>`_ with the
|
||||||
|
phone number of the developer account to use.
|
||||||
|
|
||||||
|
2. Click under API Development tools.
|
||||||
|
|
||||||
|
3. A *Create new application* window will appear. Fill in your application
|
||||||
|
details. There is no need to enter any *URL*, and only the first two
|
||||||
|
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** and Telegram won't let you revoke it.
|
||||||
|
Don't post it anywhere!
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
This API ID and hash is the one used by *your application*, not your
|
||||||
|
phone number. You can use this API ID and hash with *any* phone number
|
||||||
|
or even for bot accounts.
|
||||||
|
|
||||||
|
|
||||||
|
Editing the Code
|
||||||
|
================
|
||||||
|
|
||||||
|
This is a little introduction for those new to Python programming in general.
|
||||||
|
|
||||||
|
We will write our code inside ``hello.py``, so you can use any text
|
||||||
|
editor that you like. To run the code, use ``python3 hello.py`` from
|
||||||
|
the terminal.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
Don't call your script ``telethon.py``! Python will try to import
|
||||||
|
the client from there and it will fail with an error such as
|
||||||
|
"ImportError: cannot import name 'TelegramClient' ...".
|
||||||
|
|
||||||
|
|
||||||
|
Signing In
|
||||||
|
==========
|
||||||
|
|
||||||
|
We can finally write some code to log into our account!
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.sync import TelegramClient
|
||||||
|
|
||||||
|
# Use your own values from my.telegram.org
|
||||||
|
api_id = 12345
|
||||||
|
api_hash = '0123456789abcdef0123456789abcdef'
|
||||||
|
|
||||||
|
# The first parameter is the .session file name (absolute paths allowed)
|
||||||
|
with TelegramClient('anon', api_id, api_hash) as client:
|
||||||
|
client.send_message('me', 'Hello, myself!')
|
||||||
|
|
||||||
|
|
||||||
|
In the first line, we import the class name so we can create an instance
|
||||||
|
of the client. Then, we define variables to store our API ID and hash
|
||||||
|
conveniently.
|
||||||
|
|
||||||
|
At last, we create a new `TelegramClient <telethon.client.telegramclient.TelegramClient>`
|
||||||
|
instance and call it ``client``. We can now use the client variable
|
||||||
|
for anything that we want, such as sending a message to ourselves.
|
||||||
|
|
||||||
|
Using a ``with`` block is the preferred way to use the library. It will
|
||||||
|
automatically `start() <telethon.client.auth.AuthMethods.start>` the client,
|
||||||
|
logging or signing up if necessary.
|
||||||
|
|
||||||
|
If the ``.session`` file already existed, it will not login
|
||||||
|
again, so be aware of this if you move or rename the file!
|
||||||
|
|
||||||
|
|
||||||
|
Signing In as a Bot Account
|
||||||
|
===========================
|
||||||
|
|
||||||
|
You can also use Telethon for your bots (normal bot accounts, not users).
|
||||||
|
You will still need an API ID and hash, but the process is very similar:
|
||||||
|
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.sync import TelegramClient
|
||||||
|
|
||||||
|
api_id = 12345
|
||||||
|
api_hash = '0123456789abcdef0123456789abcdef'
|
||||||
|
bot_token = '12345:0123456789abcdef0123456789abcdef
|
||||||
|
|
||||||
|
# We have to manually call "start" if we want a explicit bot token
|
||||||
|
bot = TelegramClient('bot', api_id, api_hash).start(bot_token=bot_token)
|
||||||
|
|
||||||
|
# But then we can use the client instance as usual
|
||||||
|
with bot:
|
||||||
|
...
|
||||||
|
|
||||||
|
|
||||||
|
To get a bot account, you need to talk
|
||||||
|
with `@BotFather <https://t.me/BotFather>`_.
|
||||||
|
|
||||||
|
|
||||||
|
Signing In behind a Proxy
|
||||||
|
=========================
|
||||||
|
|
||||||
|
If you need to use a proxy to access Telegram,
|
||||||
|
you will need to `install PySocks`__ and then change:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
TelegramClient('anon', api_id, api_hash)
|
||||||
|
|
||||||
|
with
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
TelegramClient('anon', api_id, api_hash, proxy=(socks.SOCKS5, '127.0.0.1', 4444))
|
||||||
|
|
||||||
|
(of course, replacing the IP and port with the IP and port of the proxye).
|
||||||
|
|
||||||
|
The ``proxy=`` argument should be a tuple, a list or a dict,
|
||||||
|
consisting of parameters described `in PySocks usage`__.
|
||||||
|
|
||||||
|
.. __: https://github.com/Anorov/PySocks#installation
|
||||||
|
.. __: https://github.com/Anorov/PySocks#usage-1
|
161
readthedocs/basic/updates.rst
Normal file
161
readthedocs/basic/updates.rst
Normal file
|
@ -0,0 +1,161 @@
|
||||||
|
=======
|
||||||
|
Updates
|
||||||
|
=======
|
||||||
|
|
||||||
|
Updates are an important topic in a messaging platform like Telegram.
|
||||||
|
After all, you want to be notified when a new message arrives, when
|
||||||
|
a member joins, when someone starts typing, etc.
|
||||||
|
For that, you can use **events**.
|
||||||
|
|
||||||
|
.. important::
|
||||||
|
|
||||||
|
It is strongly advised to enable logging when working with events,
|
||||||
|
since exceptions in event handlers are hidden by default. Please
|
||||||
|
add the following snippet to the very top of your file:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
|
||||||
|
level=logging.WARNING)
|
||||||
|
|
||||||
|
|
||||||
|
Getting Started
|
||||||
|
===============
|
||||||
|
|
||||||
|
Let's start things with an example to automate replies:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import TelegramClient, events
|
||||||
|
|
||||||
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
|
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
async def my_event_handler(event):
|
||||||
|
if 'hello' in event.raw_text:
|
||||||
|
await event.reply('hi!')
|
||||||
|
|
||||||
|
client.start()
|
||||||
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
|
This code isn't much, but there might be some things unclear.
|
||||||
|
Let's break it down:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import TelegramClient, events
|
||||||
|
|
||||||
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
|
|
||||||
|
|
||||||
|
This is normal creation (of course, pass session name, API ID and hash).
|
||||||
|
Nothing we don't know already.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
|
||||||
|
|
||||||
|
This Python decorator will attach itself to the ``my_event_handler``
|
||||||
|
definition, and basically means that *on* a `NewMessage
|
||||||
|
<telethon.events.newmessage.NewMessage>` *event*,
|
||||||
|
the callback function you're about to define will be called:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def my_event_handler(event):
|
||||||
|
if 'hello' in event.raw_text:
|
||||||
|
await event.reply('hi!')
|
||||||
|
|
||||||
|
|
||||||
|
If a `NewMessage
|
||||||
|
<telethon.events.newmessage.NewMessage>` event occurs,
|
||||||
|
and ``'hello'`` is in the text of the message, we `reply()
|
||||||
|
<telethon.tl.custom.message.Message.reply>` to the event
|
||||||
|
with a ``'hi!'`` message.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Event handlers **must** be ``async def``. After all,
|
||||||
|
Telethon is an asynchronous library based on asyncio_,
|
||||||
|
which is a safer and often faster approach to threads.
|
||||||
|
|
||||||
|
You **must** ``await`` all method calls that use
|
||||||
|
network requests, which is most of them.
|
||||||
|
|
||||||
|
|
||||||
|
More Examples
|
||||||
|
=============
|
||||||
|
|
||||||
|
Replying to messages with hello is fun, but, can we do more?
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@client.on(events.NewMessage(outgoing=True, pattern=r'\.save'))
|
||||||
|
async def handler(event):
|
||||||
|
if event.is_reply:
|
||||||
|
replied = await event.get_reply_message()
|
||||||
|
sender = replied.sender
|
||||||
|
await client.download_profile_photo(sender)
|
||||||
|
await event.respond('Saved your photo {}'.format(sender.username))
|
||||||
|
|
||||||
|
We could also get replies. This event filters outgoing messages
|
||||||
|
(only those that we send will trigger the method), then we filter
|
||||||
|
by the regex ``r'\.save'``, which will match messages starting
|
||||||
|
with ``".save"``.
|
||||||
|
|
||||||
|
Inside the method, we check whether the event is replying to another message
|
||||||
|
or not. If it is, we get the reply message and the sender of that message,
|
||||||
|
and download their profile photo.
|
||||||
|
|
||||||
|
Let's delete messages which contain "heck". We don't allow swearing here.
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@client.on(events.NewMessage(pattern=r'(?i).*heck'))
|
||||||
|
async def handler(event):
|
||||||
|
await event.delete()
|
||||||
|
|
||||||
|
|
||||||
|
With the ``r'(?i).*heck'`` regex, we match case-insensitive
|
||||||
|
"heck" anywhere in the message. Regex is very powerful and you
|
||||||
|
can learn more at https://regexone.com/.
|
||||||
|
|
||||||
|
So far, we have only seen the `NewMessage
|
||||||
|
<telethon.events.newmessage.NewMessage>`, but there are many more
|
||||||
|
which will be covered later. This is only a small introduction to updates.
|
||||||
|
|
||||||
|
Entities
|
||||||
|
========
|
||||||
|
|
||||||
|
When you need the user or chat where an event occurred, you **must** use
|
||||||
|
the following methods:
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
# Good
|
||||||
|
chat = await event.get_chat()
|
||||||
|
sender = await event.get_sender()
|
||||||
|
chat_id = event.chat_id
|
||||||
|
sender_id = event.sender_id
|
||||||
|
|
||||||
|
# BAD. Don't do this
|
||||||
|
chat = event.chat
|
||||||
|
sender = event.sender
|
||||||
|
chat_id = event.chat.id
|
||||||
|
sender_id = event.sender.id
|
||||||
|
|
||||||
|
Events are like messages, but don't have all the information a message has!
|
||||||
|
When you manually get a message, it will have all the information it needs.
|
||||||
|
When you receive an update about a message, it **won't** have all the
|
||||||
|
information, so you have to **use the methods**, not the properties.
|
||||||
|
|
||||||
|
Make sure you understand the code seen here before continuing!
|
||||||
|
As a rule of thumb, remember that new message events behave just
|
||||||
|
like message objects, so you can do with them everything you can
|
||||||
|
do with a message object.
|
||||||
|
|
||||||
|
.. _asyncio: https://docs.python.org/3/library/asyncio.html
|
|
@ -8,7 +8,7 @@ Mastering asyncio
|
||||||
|
|
||||||
|
|
||||||
What's asyncio?
|
What's asyncio?
|
||||||
***************
|
===============
|
||||||
|
|
||||||
asyncio_ is a Python 3's built-in library. This means it's already installed if
|
asyncio_ is a Python 3's built-in library. This means it's already installed if
|
||||||
you have Python 3. Since Python 3.5, it is convenient to work with asynchronous
|
you have Python 3. Since Python 3.5, it is convenient to work with asynchronous
|
||||||
|
@ -20,7 +20,7 @@ APIs such as Telegram's makes a lot of sense this way.
|
||||||
|
|
||||||
|
|
||||||
Why asyncio?
|
Why asyncio?
|
||||||
************
|
============
|
||||||
|
|
||||||
Asynchronous IO makes a lot of sense in a library like Telethon.
|
Asynchronous IO makes a lot of sense in a library like Telethon.
|
||||||
You send a request to the server (such as "get some message"), and
|
You send a request to the server (such as "get some message"), and
|
||||||
|
@ -38,7 +38,7 @@ because tasks are smaller than threads, which are smaller than processes.
|
||||||
|
|
||||||
|
|
||||||
What are asyncio basics?
|
What are asyncio basics?
|
||||||
************************
|
========================
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ What are asyncio basics?
|
||||||
|
|
||||||
|
|
||||||
What does telethon.sync do?
|
What does telethon.sync do?
|
||||||
***************************
|
===========================
|
||||||
|
|
||||||
The moment you import any of these:
|
The moment you import any of these:
|
||||||
|
|
||||||
|
@ -133,7 +133,7 @@ running, and if the loop is running, you must ``await`` things yourself:
|
||||||
|
|
||||||
|
|
||||||
What are async, await and coroutines?
|
What are async, await and coroutines?
|
||||||
*************************************
|
=====================================
|
||||||
|
|
||||||
The ``async`` keyword lets you define asynchronous functions,
|
The ``async`` keyword lets you define asynchronous functions,
|
||||||
also known as coroutines, and also iterate over asynchronous
|
also known as coroutines, and also iterate over asynchronous
|
||||||
|
@ -212,7 +212,7 @@ The same example, but without the comment noise:
|
||||||
|
|
||||||
|
|
||||||
Can I use threads?
|
Can I use threads?
|
||||||
******************
|
==================
|
||||||
|
|
||||||
Yes, you can, but you must understand that the loops themselves are
|
Yes, you can, but you must understand that the loops themselves are
|
||||||
not thread safe. and you must be sure to know what is happening. You
|
not thread safe. and you must be sure to know what is happening. You
|
||||||
|
@ -250,7 +250,7 @@ which only works in the main thread.
|
||||||
|
|
||||||
|
|
||||||
client.run_until_disconnected() blocks!
|
client.run_until_disconnected() blocks!
|
||||||
***************************************
|
=======================================
|
||||||
|
|
||||||
All of what `client.run_until_disconnected()
|
All of what `client.run_until_disconnected()
|
||||||
<telethon.client.updates.UpdateMethods.run_until_disconnected>` does is
|
<telethon.client.updates.UpdateMethods.run_until_disconnected>` does is
|
||||||
|
@ -282,7 +282,7 @@ Of course, there are better tools to run code hourly or daily, see below.
|
||||||
|
|
||||||
|
|
||||||
What else can asyncio do?
|
What else can asyncio do?
|
||||||
*************************
|
=========================
|
||||||
|
|
||||||
Asynchronous IO is a really powerful tool, as we've seen. There are plenty
|
Asynchronous IO is a really powerful tool, as we've seen. There are plenty
|
||||||
of other useful libraries that also use asyncio_ and that you can integrate
|
of other useful libraries that also use asyncio_ and that you can integrate
|
||||||
|
@ -339,7 +339,7 @@ combine all the libraries you want. People seem to forget this simple fact!
|
||||||
|
|
||||||
|
|
||||||
Why does client.start() work outside async?
|
Why does client.start() work outside async?
|
||||||
*******************************************
|
===========================================
|
||||||
|
|
||||||
Because it's so common that it's really convenient to offer said
|
Because it's so common that it's really convenient to offer said
|
||||||
functionality by default. This means you can set up all your event
|
functionality by default. This means you can set up all your event
|
||||||
|
@ -352,7 +352,7 @@ Using the client in a ``with`` block, `start
|
||||||
all support this.
|
all support this.
|
||||||
|
|
||||||
Where can I read more?
|
Where can I read more?
|
||||||
**********************
|
======================
|
||||||
|
|
||||||
`Check out my blog post
|
`Check out my blog post
|
||||||
<https://lonamiwebs.github.io/blog/asyncio/>`_ about asyncio_, which
|
<https://lonamiwebs.github.io/blog/asyncio/>`_ about asyncio_, which
|
|
@ -1,46 +1,8 @@
|
||||||
.. _entities:
|
.. _entities:
|
||||||
|
|
||||||
=========================
|
========
|
||||||
Users, Chats and Channels
|
Entities
|
||||||
=========================
|
========
|
||||||
|
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
TL;DR; If you're here because of *"Could not find the input entity for"*,
|
|
||||||
you must ask yourself "how did I find this entity through official
|
|
||||||
applications"? Now do the same with the library. Use what applies:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with client:
|
|
||||||
# Does it have an username? Use it!
|
|
||||||
entity = client.get_entity(username)
|
|
||||||
|
|
||||||
# Do you have a conversation open with them? Get dialogs.
|
|
||||||
client.get_dialogs()
|
|
||||||
|
|
||||||
# Are they participant of some group? Get them.
|
|
||||||
client.get_participants('TelethonChat')
|
|
||||||
|
|
||||||
# Is the entity the original sender of a forwarded message? Get it.
|
|
||||||
client.get_messages('TelethonChat', 100)
|
|
||||||
|
|
||||||
# NOW you can use the ID, anywhere!
|
|
||||||
entity = client.get_entity(123456)
|
|
||||||
client.send_message(123456, 'Hi!')
|
|
||||||
|
|
||||||
Once the library has "seen" the entity, you can use their **integer** ID.
|
|
||||||
You can't use entities from IDs the library hasn't seen. You must make the
|
|
||||||
library see them *at least once* and disconnect properly. You know where
|
|
||||||
the entities are and you must tell the library. It won't guess for you.
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
|
|
||||||
Introduction
|
|
||||||
************
|
|
||||||
|
|
||||||
The library widely uses the concept of "entities". An entity will refer
|
The library widely uses the concept of "entities". An entity will refer
|
||||||
to any :tl:`User`, :tl:`Chat` or :tl:`Channel` object that the API may return
|
to any :tl:`User`, :tl:`Chat` or :tl:`Channel` object that the API may return
|
||||||
|
@ -67,8 +29,72 @@ in response to certain methods, such as :tl:`GetUsersRequest`.
|
||||||
should work to find the entity.
|
should work to find the entity.
|
||||||
|
|
||||||
|
|
||||||
Getting entities
|
.. contents::
|
||||||
****************
|
|
||||||
|
|
||||||
|
What is an Entity?
|
||||||
|
==================
|
||||||
|
|
||||||
|
A lot of methods and requests require *entities* to work. For example,
|
||||||
|
you send a message to an *entity*, get the username of an *entity*, and
|
||||||
|
so on.
|
||||||
|
|
||||||
|
There are a lot of things that work as entities: usernames, phone numbers,
|
||||||
|
chat links, invite links, IDs, and the types themselves. That is, you can
|
||||||
|
use any of those when you see an "entity" is needed.
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
Remember that the phone number must be in your contact list before you
|
||||||
|
can use it.
|
||||||
|
|
||||||
|
You should use, **from better to worse**:
|
||||||
|
|
||||||
|
1. Input entities. For example, `event.input_chat
|
||||||
|
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`,
|
||||||
|
`message.input_sender
|
||||||
|
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`,
|
||||||
|
or caching an entity you will use a lot with
|
||||||
|
``entity = await client.get_input_entity(...)``.
|
||||||
|
|
||||||
|
2. Entities. For example, if you had to get someone's
|
||||||
|
username, you can just use ``user`` or ``channel``.
|
||||||
|
It will work. Only use this option if you already have the entity!
|
||||||
|
|
||||||
|
3. IDs. This will always look the entity up from the
|
||||||
|
cache (the ``*.session`` file caches seen entities).
|
||||||
|
|
||||||
|
4. Usernames, phone numbers and links. The cache will be
|
||||||
|
used too (unless you force a `client.get_entity()
|
||||||
|
<telethon.client.users.UserMethods.get_entity>`),
|
||||||
|
but may make a request if the username, phone or link
|
||||||
|
has not been found yet.
|
||||||
|
|
||||||
|
In recent versions of the library, the following two are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
await client.send_message(event.sender_id, 'Hi')
|
||||||
|
await client.send_message(event.input_sender, 'Hi')
|
||||||
|
|
||||||
|
|
||||||
|
If you need to be 99% sure that the code will work (sometimes it's
|
||||||
|
simply impossible for the library to find the input entity), or if
|
||||||
|
you will reuse the chat a lot, consider using the following instead:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
# This method may make a network request to find the input sender.
|
||||||
|
# Properties can't make network requests, so we need a method.
|
||||||
|
sender = await event.get_input_sender()
|
||||||
|
await client.send_message(sender, 'Hi')
|
||||||
|
await client.send_message(sender, 'Hi')
|
||||||
|
|
||||||
|
|
||||||
|
Getting Entities
|
||||||
|
================
|
||||||
|
|
||||||
Through the use of the :ref:`sessions`, the library will automatically
|
Through the use of the :ref:`sessions`, the library will automatically
|
||||||
remember the ID and hash pair, along with some extra information, so
|
remember the ID and hash pair, along with some extra information, so
|
||||||
|
@ -79,6 +105,8 @@ you're able to just do this:
|
||||||
# Dialogs are the "conversations you have open".
|
# Dialogs are the "conversations you have open".
|
||||||
# This method returns a list of Dialog, which
|
# This method returns a list of Dialog, which
|
||||||
# has the .entity attribute and other information.
|
# has the .entity attribute and other information.
|
||||||
|
#
|
||||||
|
# This part is IMPORTANT, because it feels the entity cache.
|
||||||
dialogs = client.get_dialogs()
|
dialogs = client.get_dialogs()
|
||||||
|
|
||||||
# All of these work and do the same.
|
# All of these work and do the same.
|
||||||
|
@ -109,7 +137,7 @@ you're able to just do this:
|
||||||
library do its job. Use a phone from your contacts, username, ID or
|
library do its job. Use a phone from your contacts, username, ID or
|
||||||
input entity (preferred but not necessary), whatever you already have.
|
input entity (preferred but not necessary), whatever you already have.
|
||||||
|
|
||||||
All methods in the :ref:`telegram-client` call `.get_input_entity()
|
All methods in the :ref:`telethon-client` call `.get_input_entity()
|
||||||
<telethon.client.users.UserMethods.get_input_entity>` prior
|
<telethon.client.users.UserMethods.get_input_entity>` prior
|
||||||
to sending the request to save you from the hassle of doing so manually.
|
to sending the request to save you from the hassle of doing so manually.
|
||||||
That way, convenience calls such as `client.send_message('lonami', 'hi!')
|
That way, convenience calls such as `client.send_message('lonami', 'hi!')
|
||||||
|
@ -124,16 +152,12 @@ made to obtain the required information.
|
||||||
|
|
||||||
|
|
||||||
Entities vs. Input Entities
|
Entities vs. Input Entities
|
||||||
***************************
|
===========================
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
Don't worry if you don't understand this section, just remember some
|
This section is informative, but worth reading. The library
|
||||||
of the details listed here are important. When you're calling a method,
|
will transparently handle all of these details for you.
|
||||||
don't call `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
|
|
||||||
beforehand, just use the username, a phone from your contacts, or the entity
|
|
||||||
retrieved by other means like `client.get_dialogs()
|
|
||||||
<telethon.client.dialogs.DialogMethods.get_dialogs>`.
|
|
||||||
|
|
||||||
On top of the normal types, the API also make use of what they call their
|
On top of the normal types, the API also make use of what they call their
|
||||||
``Input*`` versions of objects. The input version of an entity (e.g.
|
``Input*`` versions of objects. The input version of an entity (e.g.
|
||||||
|
@ -195,8 +219,8 @@ resolve ``'username'`` with the appropriated :tl:`InputPeer`. Don't worry if
|
||||||
you don't get this yet, but remember some of the details here are important.
|
you don't get this yet, but remember some of the details here are important.
|
||||||
|
|
||||||
|
|
||||||
Full entities
|
Full Entities
|
||||||
*************
|
=============
|
||||||
|
|
||||||
In addition to :tl:`PeerUser`, :tl:`InputPeerUser`, :tl:`User` (and its
|
In addition to :tl:`PeerUser`, :tl:`InputPeerUser`, :tl:`User` (and its
|
||||||
variants for chats and channels), there is also the concept of :tl:`UserFull`.
|
variants for chats and channels), there is also the concept of :tl:`UserFull`.
|
||||||
|
@ -211,3 +235,74 @@ suggest commands to use).
|
||||||
|
|
||||||
You can get both of these by invoking :tl:`GetFullUser`, :tl:`GetFullChat`
|
You can get both of these by invoking :tl:`GetFullUser`, :tl:`GetFullChat`
|
||||||
and :tl:`GetFullChannel` respectively.
|
and :tl:`GetFullChannel` respectively.
|
||||||
|
|
||||||
|
|
||||||
|
Accessing Entities
|
||||||
|
==================
|
||||||
|
|
||||||
|
Although it's explicitly noted in the documentation that messages
|
||||||
|
*subclass* `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
|
||||||
|
and `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>`,
|
||||||
|
some people still don't get inheritance.
|
||||||
|
|
||||||
|
When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
|
||||||
|
it means that the class you're looking at, *also* can act as the class it
|
||||||
|
bases. In this case, `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
|
||||||
|
knows how to get the *chat* where a thing belongs to.
|
||||||
|
|
||||||
|
So, a `Message <telethon.tl.custom.message.Message>` is a
|
||||||
|
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`.
|
||||||
|
That means you can do this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
message.is_private
|
||||||
|
message.chat_id
|
||||||
|
message.get_chat()
|
||||||
|
# ...etc
|
||||||
|
|
||||||
|
`SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
message.user_id
|
||||||
|
message.get_input_user()
|
||||||
|
message.user
|
||||||
|
# ...etc
|
||||||
|
|
||||||
|
Quite a few things implement them, so it makes sense to reuse the code.
|
||||||
|
For example, all events (except raw updates) implement `ChatGetter
|
||||||
|
<telethon.tl.custom.chatgetter.ChatGetter>` since all events occur
|
||||||
|
in some chat.
|
||||||
|
|
||||||
|
|
||||||
|
Summary
|
||||||
|
=======
|
||||||
|
|
||||||
|
TL;DR; If you're here because of *"Could not find the input entity for"*,
|
||||||
|
you must ask yourself "how did I find this entity through official
|
||||||
|
applications"? Now do the same with the library. Use what applies:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with client:
|
||||||
|
# Does it have an username? Use it!
|
||||||
|
entity = client.get_entity(username)
|
||||||
|
|
||||||
|
# Do you have a conversation open with them? Get dialogs.
|
||||||
|
client.get_dialogs()
|
||||||
|
|
||||||
|
# Are they participant of some group? Get them.
|
||||||
|
client.get_participants('TelethonChat')
|
||||||
|
|
||||||
|
# Is the entity the original sender of a forwarded message? Get it.
|
||||||
|
client.get_messages('TelethonChat', 100)
|
||||||
|
|
||||||
|
# NOW you can use the ID, anywhere!
|
||||||
|
entity = client.get_entity(123456)
|
||||||
|
client.send_message(123456, 'Hi!')
|
||||||
|
|
||||||
|
Once the library has "seen" the entity, you can use their **integer** ID.
|
||||||
|
You can't use entities from IDs the library hasn't seen. You must make the
|
||||||
|
library see them *at least once* and disconnect properly. You know where
|
||||||
|
the entities are and you must tell the library. It won't guess for you.
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _rpc-errors:
|
||||||
|
|
||||||
==========
|
==========
|
||||||
RPC Errors
|
RPC Errors
|
||||||
==========
|
==========
|
||||||
|
@ -6,7 +8,7 @@ RPC stands for Remote Procedure Call, and when the library raises
|
||||||
a ``RPCError``, it's because you have invoked some of the API
|
a ``RPCError``, it's 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). All the errors are
|
something went wrong on Telegram's server). All the errors are
|
||||||
available in :ref:`telethon-errors-package`, but some examples are:
|
available in :ref:`telethon-errors`, but some examples are:
|
||||||
|
|
||||||
- ``FloodWaitError`` (420), the same request was repeated many times.
|
- ``FloodWaitError`` (420), the same request was repeated many times.
|
||||||
Must wait ``.seconds`` (you can access this attribute). For example:
|
Must wait ``.seconds`` (you can access this attribute). For example:
|
||||||
|
@ -43,3 +45,33 @@ If the error is not recognised, it will only be an ``RPCError``.
|
||||||
You can refer to all errors from Python through the ``telethon.errors``
|
You can refer to all errors from Python through the ``telethon.errors``
|
||||||
module. If you don't know what attributes they have, try printing their
|
module. If you don't know what attributes they have, try printing their
|
||||||
dir (like ``print(dir(e))``).
|
dir (like ``print(dir(e))``).
|
||||||
|
|
||||||
|
Avoiding Limits
|
||||||
|
===============
|
||||||
|
|
||||||
|
Don't spam. You won't get ``FloodWaitError`` or your account banned or
|
||||||
|
deleted if you use the library *for legit use cases*. Make cool tools.
|
||||||
|
Don't spam! Nobody knows the exact limits for all requests since they
|
||||||
|
depend on a lot of factors, so don't bother asking.
|
||||||
|
|
||||||
|
Still, if you do have a legit use case and still get those errors, the
|
||||||
|
library will automatically sleep when they are smaller than 60 seconds
|
||||||
|
by default. You can set different "auto-sleep" thresholds:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client.flood_sleep_threshold = 0 # Don't auto-sleep
|
||||||
|
client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
|
||||||
|
|
||||||
|
You can also except it and act as you prefer:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.errors import FloodWaitError
|
||||||
|
try:
|
||||||
|
...
|
||||||
|
except FloodWaitError as e:
|
||||||
|
print('Flood waited for', e.seconds)
|
||||||
|
quit(1)
|
||||||
|
|
||||||
|
VoIP numbers are very limited, and some countries are more limited too.
|
|
@ -1,21 +1,21 @@
|
||||||
.. _accessing-the-full-api:
|
.. _full-api:
|
||||||
|
|
||||||
======================
|
============
|
||||||
Accessing the Full API
|
The Full API
|
||||||
======================
|
============
|
||||||
|
|
||||||
.. important::
|
.. important::
|
||||||
|
|
||||||
While you have access to this, you should always use the friendly
|
While you have access to this, you should always use the friendly
|
||||||
methods listed on :ref:`telethon-client` unless you have a better
|
methods listed on :ref:`client-ref` unless you have a better reason
|
||||||
reason not to, like a method not existing or you wanting more control.
|
not to, like a method not existing or you wanting more control.
|
||||||
|
|
||||||
|
|
||||||
The :ref:`TelegramClient <telethon-client>` doesn't offer a method for
|
The :ref:`telethon-client` doesn't offer a method for every single request
|
||||||
every single request the Telegram API supports. However, it's very simple to
|
the Telegram API supports. However, it's very simple to *call* or *invoke*
|
||||||
*call* or *invoke* any request. Whenever you need something, don't forget to
|
any request. Whenever you need something, don't forget to `check the documentation`_
|
||||||
`check the documentation`__ and look for the `method you need`__. There you
|
and look for the `method you need`_. There you can go through a sorted list
|
||||||
can go through a sorted list of everything you can do.
|
of everything you can do.
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
@ -39,9 +39,9 @@ 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
|
Say `client.send_message()
|
||||||
<telethon.client.messages.MessageMethods.send_message>` didn't exist,
|
<telethon.client.messages.MessageMethods.send_message>` didn't exist,
|
||||||
we could use the `search`__ to look for "message". There we would find
|
we could `use the search`_ to look for "message". There we would find
|
||||||
:tl:`SendMessageRequest`, which we can work with.
|
:tl:`SendMessageRequest`, 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
|
||||||
|
@ -73,7 +73,7 @@ construct one, for instance:
|
||||||
|
|
||||||
peer = InputPeerUser(user_id, user_hash)
|
peer = InputPeerUser(user_id, user_hash)
|
||||||
|
|
||||||
Or we call `client.get_input_entity
|
Or we call `client.get_input_entity()
|
||||||
<telethon.client.users.UserMethods.get_input_entity>`:
|
<telethon.client.users.UserMethods.get_input_entity>`:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -84,10 +84,10 @@ Or we call `client.get_input_entity
|
||||||
|
|
||||||
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
|
||||||
:tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
|
:tl:`InputUser`, :tl:`InputChat`, or so on, this is why using
|
||||||
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`
|
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`
|
||||||
is more straightforward (and often immediate, if you've seen the user before,
|
is more straightforward (and often immediate, if you've seen the user before,
|
||||||
know their ID, etc.). If you also **need** to have information about the whole
|
know their ID, etc.). If you also **need** to have information about the whole
|
||||||
user, use `client.get_entity <telethon.client.users.UserMethods.get_entity>`
|
user, use `client.get_entity() <telethon.client.users.UserMethods.get_entity>`
|
||||||
instead:
|
instead:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
@ -114,7 +114,7 @@ every time its used, simply call `telethon.utils.get_input_peer`:
|
||||||
|
|
||||||
After this small parenthesis about `client.get_entity
|
After this small parenthesis about `client.get_entity
|
||||||
<telethon.client.users.UserMethods.get_entity>` versus
|
<telethon.client.users.UserMethods.get_entity>` versus
|
||||||
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`,
|
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`,
|
||||||
we have everything we need. To invoke our
|
we have everything we need. To invoke our
|
||||||
request we do:
|
request we do:
|
||||||
|
|
||||||
|
@ -156,7 +156,7 @@ This can further be simplified to:
|
||||||
|
|
||||||
|
|
||||||
Requests in Parallel
|
Requests in Parallel
|
||||||
********************
|
====================
|
||||||
|
|
||||||
The library will automatically merge outgoing requests into a single
|
The library will automatically merge outgoing requests into a single
|
||||||
*container*. Telegram's API supports sending multiple requests in a
|
*container*. Telegram's API supports sending multiple requests in a
|
||||||
|
@ -224,6 +224,6 @@ and still access the successful results:
|
||||||
# The second request failed.
|
# The second request failed.
|
||||||
second = e.exceptions[1]
|
second = e.exceptions[1]
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon
|
.. _check the documentation: https://lonamiwebs.github.io/Telethon
|
||||||
__ https://lonamiwebs.github.io/Telethon/methods/index.html
|
.. _method you need: https://lonamiwebs.github.io/Telethon/methods/index.html
|
||||||
__ https://lonamiwebs.github.io/Telethon/?q=message&redirect=no
|
.. _use the search: https://lonamiwebs.github.io/Telethon/?q=message&redirect=no
|
|
@ -6,8 +6,11 @@ Session Files
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
What are sessions?
|
They are an important part for the library to be efficient, such as caching
|
||||||
******************
|
and handling your authorization key (or you would have to login every time!).
|
||||||
|
|
||||||
|
What are Sessions?
|
||||||
|
==================
|
||||||
|
|
||||||
The first parameter you pass to the constructor of the
|
The first parameter you pass to the constructor of the
|
||||||
:ref:`TelegramClient <telethon-client>` is
|
:ref:`TelegramClient <telethon-client>` is
|
||||||
|
@ -43,7 +46,7 @@ by setting ``client.session.save_entities = False``.
|
||||||
|
|
||||||
|
|
||||||
Different Session Storage
|
Different Session Storage
|
||||||
*************************
|
=========================
|
||||||
|
|
||||||
If you don't want to use the default SQLite session storage, you can also use
|
If you don't want to use the default SQLite session storage, you can also use
|
||||||
one of the other implementations or implement your own storage.
|
one of the other implementations or implement your own storage.
|
||||||
|
@ -54,13 +57,15 @@ the session name.
|
||||||
|
|
||||||
Telethon contains three implementations of the abstract ``Session`` class:
|
Telethon contains three implementations of the abstract ``Session`` class:
|
||||||
|
|
||||||
* ``MemorySession``: stores session data within memory.
|
.. currentmodule:: telethon.sessions
|
||||||
* ``SQLiteSession``: stores sessions within on-disk SQLite databases. Default.
|
|
||||||
* ``StringSession``: stores session data within memory,
|
* `MemorySession <memory.MemorySession>`: stores session data within memory.
|
||||||
|
* `SQLiteSession <sqlite.SQLiteSession>`: stores sessions within on-disk SQLite databases. Default.
|
||||||
|
* `StringSession <string.StringSession>`: stores session data within memory,
|
||||||
but can be saved as a string.
|
but can be saved as a string.
|
||||||
|
|
||||||
You can import these ``from telethon.sessions``. For example, using the
|
You can import these ``from telethon.sessions``. For example, using the
|
||||||
``StringSession`` is done as follows:
|
`StringSession <string.StringSession>` is done as follows:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
||||||
|
@ -91,25 +96,27 @@ There are other community-maintained implementations available:
|
||||||
* `Redis <https://github.com/ezdev128/telethon-session-redis>`_:
|
* `Redis <https://github.com/ezdev128/telethon-session-redis>`_:
|
||||||
stores all sessions in a single Redis data store.
|
stores all sessions in a single Redis data store.
|
||||||
|
|
||||||
|
|
||||||
Creating your Own Storage
|
Creating your Own Storage
|
||||||
*************************
|
=========================
|
||||||
|
|
||||||
The easiest way to create your own storage implementation is to use
|
The easiest way to create your own storage implementation is to use
|
||||||
``MemorySession`` as the base and check out how ``SQLiteSession`` or
|
`MemorySession <memory.MemorySession>` as the base and check out how
|
||||||
one of the community-maintained implementations work. You can find the
|
`SQLiteSession <sqlite.SQLiteSession>` or one of the community-maintained
|
||||||
relevant Python files under the ``sessions`` directory in Telethon.
|
implementations work. You can find the relevant Python files under the
|
||||||
|
``sessions/`` directory in the Telethon's repository.
|
||||||
|
|
||||||
After you have made your own implementation, you can add it to the
|
After you have made your own implementation, you can add it to the
|
||||||
community-maintained session implementation list above with a pull request.
|
community-maintained session implementation list above with a pull request.
|
||||||
|
|
||||||
|
|
||||||
String Sessions
|
String Sessions
|
||||||
***************
|
===============
|
||||||
|
|
||||||
``StringSession`` are a convenient way to embed your login credentials
|
`StringSession <string.StringSession>` are a convenient way to embed your
|
||||||
directly into your code for extremely easy portability, since all they
|
login credentials directly into your code for extremely easy portability,
|
||||||
take is a string to be able to login without asking for your phone and
|
since all they take is a string to be able to login without asking for your
|
||||||
code (or faster start if you're using a bot token).
|
phone and code (or faster start if you're using a bot token).
|
||||||
|
|
||||||
The easiest way to generate a string session is as follows:
|
The easiest way to generate a string session is as follows:
|
||||||
|
|
100
readthedocs/concepts/strings.rst
Normal file
100
readthedocs/concepts/strings.rst
Normal file
|
@ -0,0 +1,100 @@
|
||||||
|
======================
|
||||||
|
String-based Debugging
|
||||||
|
======================
|
||||||
|
|
||||||
|
Debugging is *really* important. Telegram's API is really big and there
|
||||||
|
is a lot of things that you should know. Such as, what attributes or fields
|
||||||
|
does a result have? Well, the easiest thing to do is printing it:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
user = client.get_entity('Lonami')
|
||||||
|
print(user)
|
||||||
|
|
||||||
|
That will show a huge **string** similar to the following:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
|
||||||
|
|
||||||
|
That's a lot of text. But as you can see, all the properties are there.
|
||||||
|
So if you want the username you **don't use regex** or anything like
|
||||||
|
splitting ``str(user)`` to get what you want. You just access the
|
||||||
|
attribute you need:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
username = user.username
|
||||||
|
|
||||||
|
Can we get better than the shown string, though? Yes!
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
print(user.stringify())
|
||||||
|
|
||||||
|
Will show a much better:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
User(
|
||||||
|
id=10885151,
|
||||||
|
is_self=False,
|
||||||
|
contact=False,
|
||||||
|
mutual_contact=False,
|
||||||
|
deleted=False,
|
||||||
|
bot=False,
|
||||||
|
bot_chat_history=False,
|
||||||
|
bot_nochats=False,
|
||||||
|
verified=False,
|
||||||
|
restricted=False,
|
||||||
|
min=False,
|
||||||
|
bot_inline_geo=False,
|
||||||
|
access_hash=123456789012345678,
|
||||||
|
first_name='Lonami',
|
||||||
|
last_name=None,
|
||||||
|
username='Lonami',
|
||||||
|
phone=None,
|
||||||
|
photo=UserProfilePhoto(
|
||||||
|
photo_id=123456789012345678,
|
||||||
|
photo_small=FileLocation(
|
||||||
|
dc_id=4,
|
||||||
|
volume_id=123456789,
|
||||||
|
local_id=123456789,
|
||||||
|
secret=-123456789012345678
|
||||||
|
),
|
||||||
|
photo_big=FileLocation(
|
||||||
|
dc_id=4,
|
||||||
|
volume_id=123456789,
|
||||||
|
local_id=123456789,
|
||||||
|
secret=123456789012345678
|
||||||
|
)
|
||||||
|
),
|
||||||
|
status=UserStatusOffline(
|
||||||
|
was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
|
||||||
|
),
|
||||||
|
bot_info_version=None,
|
||||||
|
restriction_reason=None,
|
||||||
|
bot_inline_placeholder=None,
|
||||||
|
lang_code=None
|
||||||
|
)
|
||||||
|
|
||||||
|
Now it's easy to see how we could get, for example,
|
||||||
|
the ``was_online`` time. It's inside ``status``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
online_at = user.status.was_online
|
||||||
|
|
||||||
|
You don't need to print everything to see what all the possible values
|
||||||
|
can be. You can just search in http://lonamiwebs.github.io/Telethon/.
|
||||||
|
|
||||||
|
Remember that you can use Python's `isinstance
|
||||||
|
<https://docs.python.org/3/library/functions.html#isinstance>`_
|
||||||
|
to check the type of something. For example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import types
|
||||||
|
|
||||||
|
if isinstance(user.status, types.UserStatusOffline):
|
||||||
|
print(user.status.was_online)
|
229
readthedocs/concepts/updates.rst
Normal file
229
readthedocs/concepts/updates.rst
Normal file
|
@ -0,0 +1,229 @@
|
||||||
|
================
|
||||||
|
Updates in Depth
|
||||||
|
================
|
||||||
|
|
||||||
|
Properties vs. Methods
|
||||||
|
======================
|
||||||
|
|
||||||
|
The event shown above acts just like a `custom.Message
|
||||||
|
<telethon.tl.custom.message.Message>`, which means you
|
||||||
|
can access all the properties it has, like ``.sender``.
|
||||||
|
|
||||||
|
**However** events are different to other methods in the client, like
|
||||||
|
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
|
||||||
|
Events *may not* send information about the sender or chat, which means it
|
||||||
|
can be ``None``, but all the methods defined in the client always have this
|
||||||
|
information so it doesn't need to be re-fetched. For this reason, you have
|
||||||
|
``get_`` methods, which will make a network call if necessary.
|
||||||
|
|
||||||
|
In short, you should do this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
async def handler(event):
|
||||||
|
# event.input_chat may be None, use event.get_input_chat()
|
||||||
|
chat = await event.get_input_chat()
|
||||||
|
sender = await event.get_sender()
|
||||||
|
buttons = await event.get_buttons()
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
async for message in client.iter_messages('me', 10):
|
||||||
|
# Methods from the client always have these properties ready
|
||||||
|
chat = message.input_chat
|
||||||
|
sender = message.sender
|
||||||
|
buttons = message.buttons
|
||||||
|
|
||||||
|
Notice, properties (`message.sender
|
||||||
|
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
|
||||||
|
methods (`message.get_sender
|
||||||
|
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
|
||||||
|
and you should use methods in events for these properties that may need network.
|
||||||
|
|
||||||
|
Events Without the client
|
||||||
|
=========================
|
||||||
|
|
||||||
|
The code of your application starts getting big, so you decide to
|
||||||
|
separate the handlers into different files. But how can you access
|
||||||
|
the client from these files? You don't need to! Just `events.register
|
||||||
|
<telethon.events.register>` them:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# handlers/welcome.py
|
||||||
|
from telethon import events
|
||||||
|
|
||||||
|
@events.register(events.NewMessage('(?i)hello'))
|
||||||
|
async def handler(event):
|
||||||
|
client = event.client
|
||||||
|
await event.respond('Hey!')
|
||||||
|
await client.send_message('me', 'I said hello to someone')
|
||||||
|
|
||||||
|
|
||||||
|
Registering events is a way of saying "this method is an event handler".
|
||||||
|
You can use `telethon.events.is_handler` to check if any method is a handler.
|
||||||
|
You can think of them as a different approach to Flask's blueprints.
|
||||||
|
|
||||||
|
It's important to note that this does **not** add the handler to any client!
|
||||||
|
You never specified the client on which the handler should be used. You only
|
||||||
|
declared that it is a handler, and its type.
|
||||||
|
|
||||||
|
To actually use the handler, you need to `client.add_event_handler
|
||||||
|
<telethon.client.updates.UpdateMethods.add_event_handler>` to the
|
||||||
|
client (or clients) where they should be added to:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# main.py
|
||||||
|
from telethon import TelegramClient
|
||||||
|
import handlers.welcome
|
||||||
|
|
||||||
|
with TelegramClient(...) as client:
|
||||||
|
client.add_event_handler(handlers.welcome.handler)
|
||||||
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
|
This also means that you can register an event handler once and
|
||||||
|
then add it to many clients without re-declaring the event.
|
||||||
|
|
||||||
|
|
||||||
|
Events Without Decorators
|
||||||
|
=========================
|
||||||
|
|
||||||
|
If for any reason you don't want to use `telethon.events.register`,
|
||||||
|
you can explicitly pass the event handler to use to the mentioned
|
||||||
|
`client.add_event_handler
|
||||||
|
<telethon.client.updates.UpdateMethods.add_event_handler>`:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import TelegramClient, events
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
...
|
||||||
|
|
||||||
|
with TelegramClient(...) as client:
|
||||||
|
client.add_event_handler(handler, events.NewMessage)
|
||||||
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
|
Similarly, you also have `client.remove_event_handler
|
||||||
|
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
||||||
|
and `client.list_event_handlers
|
||||||
|
<telethon.client.updates.UpdateMethods.list_event_handlers>`.
|
||||||
|
|
||||||
|
The ``event`` argument is optional in all three methods and defaults to
|
||||||
|
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
|
||||||
|
removing (so all callbacks would be removed).
|
||||||
|
|
||||||
|
.. note::
|
||||||
|
|
||||||
|
The ``event`` type is ignored in `client.add_event_handler
|
||||||
|
<telethon.client.updates.UpdateMethods.add_event_handler>`
|
||||||
|
if you have used `telethon.events.register` on the ``callback``
|
||||||
|
before, since that's the point of using such method at all.
|
||||||
|
|
||||||
|
|
||||||
|
Stopping Propagation of Updates
|
||||||
|
===============================
|
||||||
|
|
||||||
|
There might be cases when an event handler is supposed to be used solitary and
|
||||||
|
it makes no sense to process any other handlers in the chain. For this case,
|
||||||
|
it is possible to raise a `telethon.events.StopPropagation` exception which
|
||||||
|
will cause the propagation of the update through your handlers to stop:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon.events import StopPropagation
|
||||||
|
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
async def _(event):
|
||||||
|
# ... some conditions
|
||||||
|
await event.delete()
|
||||||
|
|
||||||
|
# Other handlers won't have an event to work with
|
||||||
|
raise StopPropagation
|
||||||
|
|
||||||
|
@client.on(events.NewMessage)
|
||||||
|
async def _(event):
|
||||||
|
# Will never be reached, because it is the second handler
|
||||||
|
# in the chain.
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
Remember to check :ref:`telethon-events` if you're looking for
|
||||||
|
the methods reference.
|
||||||
|
|
||||||
|
Understanding asyncio
|
||||||
|
=====================
|
||||||
|
|
||||||
|
|
||||||
|
With ``asyncio``, the library has several tasks running in the background.
|
||||||
|
One task is used for sending requests, another task is used to receive them,
|
||||||
|
and a third one is used to handle updates.
|
||||||
|
|
||||||
|
To handle updates, you must keep your script running. You can do this in
|
||||||
|
several ways. For instance, if you are *not* running ``asyncio``'s event
|
||||||
|
loop, you should use `client.run_until_disconnected
|
||||||
|
<telethon.client.updates.UpdateMethods.run_until_disconnected>`:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from telethon import TelegramClient
|
||||||
|
|
||||||
|
client = TelegramClient(...)
|
||||||
|
...
|
||||||
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
|
Behind the scenes, this method is ``await``'ing on the `client.disconnected
|
||||||
|
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>` property,
|
||||||
|
so the code above and the following are equivalent:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import asyncio
|
||||||
|
from telethon import TelegramClient
|
||||||
|
|
||||||
|
client = TelegramClient(...)
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await client.disconnected
|
||||||
|
|
||||||
|
loop = asyncio.get_event_loop()
|
||||||
|
loop.run_until_complete(main())
|
||||||
|
|
||||||
|
|
||||||
|
You could also run `client.disconnected
|
||||||
|
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
|
||||||
|
until it completed.
|
||||||
|
|
||||||
|
But if you don't want to ``await``, then you should know what you want
|
||||||
|
to be doing instead! What matters is that you shouldn't let your script
|
||||||
|
die. If you don't care about updates, you don't need any of this.
|
||||||
|
|
||||||
|
Notice that unlike `client.disconnected
|
||||||
|
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`,
|
||||||
|
`client.run_until_disconnected
|
||||||
|
<telethon.client.updates.UpdateMethods.run_until_disconnected>` will
|
||||||
|
handle ``KeyboardInterrupt`` with you. This method is special and can
|
||||||
|
also be ran while the loop is running, so you can do this:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def main():
|
||||||
|
await client.run_until_disconnected()
|
||||||
|
|
||||||
|
loop.run_until_complete(main())
|
||||||
|
|
||||||
|
Sequential Updates
|
||||||
|
==================
|
||||||
|
|
||||||
|
If you need to process updates sequentially (i.e. not in parallel),
|
||||||
|
you should set ``sequential_updates=True`` when creating the client:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
with TelegramClient(..., sequential_updates=True) as client:
|
||||||
|
...
|
|
@ -61,7 +61,7 @@ master_doc = 'index'
|
||||||
|
|
||||||
# General information about the project.
|
# General information about the project.
|
||||||
project = 'Telethon'
|
project = 'Telethon'
|
||||||
copyright = '2017, Lonami'
|
copyright = '2017 - 2019, Lonami'
|
||||||
author = 'Lonami'
|
author = 'Lonami'
|
||||||
|
|
||||||
# The version info for the project you're documenting, acts as replacement for
|
# The version info for the project you're documenting, acts as replacement for
|
||||||
|
|
|
@ -4,7 +4,7 @@ Project Structure
|
||||||
|
|
||||||
|
|
||||||
Main interface
|
Main interface
|
||||||
**************
|
==============
|
||||||
|
|
||||||
The library itself is under the ``telethon/`` directory. The
|
The library itself is under the ``telethon/`` directory. The
|
||||||
``__init__.py`` file there exposes the main ``TelegramClient``, a class
|
``__init__.py`` file there exposes the main ``TelegramClient``, a class
|
||||||
|
@ -34,7 +34,7 @@ which outgoing messages should be sent (how to encode their length and
|
||||||
their body, if they're further encrypted).
|
their body, if they're further encrypted).
|
||||||
|
|
||||||
Auto-generated code
|
Auto-generated code
|
||||||
*******************
|
===================
|
||||||
|
|
||||||
The files under ``telethon_generator/`` are used to generate the code
|
The files under ``telethon_generator/`` are used to generate the code
|
||||||
that gets placed under ``telethon/tl/``. The parsers take in files in
|
that gets placed under ``telethon/tl/``. The parsers take in files in
|
|
@ -19,7 +19,7 @@ there by `@vysheng <https://github.com/vysheng>`__,
|
||||||
has been moved to `BitBucket <https://bitbucket.org/vysheng/tdcli>`__.
|
has been moved to `BitBucket <https://bitbucket.org/vysheng/tdcli>`__.
|
||||||
|
|
||||||
C++
|
C++
|
||||||
***
|
===
|
||||||
|
|
||||||
The newest (and official) library, written from scratch, is called
|
The newest (and official) library, written from scratch, is called
|
||||||
`tdlib <https://github.com/tdlib/td>`__ and is what the Telegram X
|
`tdlib <https://github.com/tdlib/td>`__ and is what the Telegram X
|
||||||
|
@ -27,7 +27,7 @@ uses. You can find more information in the official documentation,
|
||||||
published `here <https://core.telegram.org/tdlib/docs/>`__.
|
published `here <https://core.telegram.org/tdlib/docs/>`__.
|
||||||
|
|
||||||
JavaScript
|
JavaScript
|
||||||
**********
|
==========
|
||||||
|
|
||||||
`@zerobias <https://github.com/zerobias>`__ is working on
|
`@zerobias <https://github.com/zerobias>`__ is working on
|
||||||
`telegram-mtproto <https://github.com/zerobias/telegram-mtproto>`__,
|
`telegram-mtproto <https://github.com/zerobias/telegram-mtproto>`__,
|
||||||
|
@ -35,7 +35,7 @@ a work-in-progress JavaScript library installable via
|
||||||
`npm <https://www.npmjs.com/>`__.
|
`npm <https://www.npmjs.com/>`__.
|
||||||
|
|
||||||
Kotlin
|
Kotlin
|
||||||
******
|
======
|
||||||
|
|
||||||
`Kotlogram <https://github.com/badoualy/kotlogram>`__ is a Telegram
|
`Kotlogram <https://github.com/badoualy/kotlogram>`__ is a Telegram
|
||||||
implementation written in Kotlin (one of the
|
implementation written in Kotlin (one of the
|
||||||
|
@ -46,7 +46,7 @@ languages for
|
||||||
yet working.
|
yet working.
|
||||||
|
|
||||||
PHP
|
PHP
|
||||||
***
|
===
|
||||||
|
|
||||||
A PHP implementation is also available thanks to
|
A PHP implementation is also available thanks to
|
||||||
`@danog <https://github.com/danog>`__ and his
|
`@danog <https://github.com/danog>`__ and his
|
||||||
|
@ -55,7 +55,7 @@ a very nice `online
|
||||||
documentation <https://daniil.it/MadelineProto/API_docs/>`__ too.
|
documentation <https://daniil.it/MadelineProto/API_docs/>`__ too.
|
||||||
|
|
||||||
Python
|
Python
|
||||||
******
|
======
|
||||||
|
|
||||||
A fairly new (as of the end of 2017) Telegram library written from the
|
A fairly new (as of the end of 2017) Telegram library written from the
|
||||||
ground up in Python by
|
ground up in Python by
|
||||||
|
@ -66,7 +66,7 @@ sad to see you go, but it would be nice to know what you miss from each
|
||||||
other library in either one so both can improve.
|
other library in either one so both can improve.
|
||||||
|
|
||||||
Rust
|
Rust
|
||||||
****
|
====
|
||||||
|
|
||||||
Yet another work-in-progress implementation, this time for Rust thanks
|
Yet another work-in-progress implementation, this time for Rust thanks
|
||||||
to `@JuanPotato <https://github.com/JuanPotato>`__ under the fancy
|
to `@JuanPotato <https://github.com/JuanPotato>`__ under the fancy
|
|
@ -5,13 +5,13 @@ Working with Chats and Channels
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
These examples assume you have read :ref:`accessing-the-full-api`.
|
These examples assume you have read :ref:`full-api`.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
Joining a chat or channel
|
Joining a chat or channel
|
||||||
*************************
|
=========================
|
||||||
|
|
||||||
Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a
|
Note that :tl:`Chat` are normal groups, and :tl:`Channel` are a
|
||||||
special form of :tl:`Chat`, which can also be super-groups if
|
special form of :tl:`Chat`, which can also be super-groups if
|
||||||
|
@ -19,7 +19,7 @@ their ``megagroup`` member is ``True``.
|
||||||
|
|
||||||
|
|
||||||
Joining a public channel
|
Joining a public channel
|
||||||
************************
|
========================
|
||||||
|
|
||||||
Once you have the :ref:`entity <entities>` of the channel you want to join
|
Once you have the :ref:`entity <entities>` of the channel you want to join
|
||||||
to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
|
to, you can make use of the :tl:`JoinChannelRequest` to join such channel:
|
||||||
|
@ -41,7 +41,7 @@ __ https://lonamiwebs.github.io/Telethon/methods/channels/index.html
|
||||||
|
|
||||||
|
|
||||||
Joining a private chat or channel
|
Joining a private chat or channel
|
||||||
*********************************
|
=================================
|
||||||
|
|
||||||
If all you have is a link like this one:
|
If all you have is a link like this one:
|
||||||
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
|
``https://t.me/joinchat/AAAAAFFszQPyPEZ7wgxLtd``, you already have
|
||||||
|
@ -57,7 +57,7 @@ example, is the ``hash`` of the chat or channel. Now you can use
|
||||||
|
|
||||||
|
|
||||||
Adding someone else to such chat or channel
|
Adding someone else to such chat or channel
|
||||||
*******************************************
|
===========================================
|
||||||
|
|
||||||
If you don't want to add yourself, maybe because you're already in,
|
If you don't want to add yourself, maybe because you're already in,
|
||||||
you can always add someone else with the :tl:`AddChatUserRequest`, which
|
you can always add someone else with the :tl:`AddChatUserRequest`, which
|
||||||
|
@ -86,7 +86,7 @@ use is very straightforward, or :tl:`InviteToChannelRequest` for channels:
|
||||||
|
|
||||||
|
|
||||||
Checking a link without joining
|
Checking a link without joining
|
||||||
*******************************
|
===============================
|
||||||
|
|
||||||
If you don't need to join but rather check whether it's a group or a
|
If you don't need to join but rather check whether it's a group or a
|
||||||
channel, you can use the :tl:`CheckChatInviteRequest`, which takes in
|
channel, you can use the :tl:`CheckChatInviteRequest`, which takes in
|
||||||
|
@ -94,7 +94,7 @@ the hash of said channel or group.
|
||||||
|
|
||||||
|
|
||||||
Admin Permissions
|
Admin Permissions
|
||||||
*****************
|
=================
|
||||||
|
|
||||||
Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`:
|
Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`:
|
||||||
|
|
||||||
|
@ -152,7 +152,7 @@ Giving or revoking admin permissions can be done with the :tl:`EditAdminRequest`
|
||||||
|
|
||||||
|
|
||||||
Restricting Users
|
Restricting Users
|
||||||
*****************
|
=================
|
||||||
|
|
||||||
Similar to how you give or revoke admin permissions, you can edit the
|
Similar to how you give or revoke admin permissions, you can edit the
|
||||||
banned rights of a user through :tl:`EditBannedRequest` and its parameter
|
banned rights of a user through :tl:`EditBannedRequest` and its parameter
|
||||||
|
@ -203,7 +203,7 @@ https://core.telegram.org/bots/api#restrictchatmember.
|
||||||
|
|
||||||
|
|
||||||
Kicking a member
|
Kicking a member
|
||||||
****************
|
================
|
||||||
|
|
||||||
Telegram doesn't actually have a request to kick a user from a group.
|
Telegram doesn't actually have a request to kick a user from a group.
|
||||||
Instead, you need to restrict them so they can't see messages. Any date
|
Instead, you need to restrict them so they can't see messages. Any date
|
||||||
|
@ -228,7 +228,7 @@ __ https://lonamiwebs.github.io/Telethon/constructors/channel_admin_rights.html
|
||||||
|
|
||||||
|
|
||||||
Increasing View Count in a Channel
|
Increasing View Count in a Channel
|
||||||
**********************************
|
==================================
|
||||||
|
|
||||||
It has been asked `quite`__ `a few`__ `times`__ (really, `many`__), and
|
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
|
while I don't understand why so many people ask this, the solution is to
|
|
@ -1,3 +1,5 @@
|
||||||
|
.. _telethon_projects:
|
||||||
|
|
||||||
=======================
|
=======================
|
||||||
Projects using Telethon
|
Projects using Telethon
|
||||||
=======================
|
=======================
|
||||||
|
@ -15,10 +17,10 @@ the library.
|
||||||
.. _projects-telegram-export:
|
.. _projects-telegram-export:
|
||||||
|
|
||||||
telethon_examples/
|
telethon_examples/
|
||||||
******************
|
==================
|
||||||
|
|
||||||
`Link <https://github.com/LonamiWebs/Telethon/tree/master/telethon_examples>`_ /
|
`telethon_examples <https://github.com/LonamiWebs/Telethon/tree/master/telethon_examples>`_ /
|
||||||
`Author's website <https://lonamiwebs.github.io>`_
|
`LonamiWebs' site <https://lonamiwebs.github.io>`_
|
||||||
|
|
||||||
This documentation is not the only place where you can find useful code
|
This documentation is not the only place where you can find useful code
|
||||||
snippets using the library. The main repository also has a folder with
|
snippets using the library. The main repository also has a folder with
|
||||||
|
@ -26,10 +28,10 @@ some cool examples (even a Tkinter GUI!) which you can download, edit
|
||||||
and run to learn and play with them.
|
and run to learn and play with them.
|
||||||
|
|
||||||
telegram-export
|
telegram-export
|
||||||
***************
|
===============
|
||||||
|
|
||||||
`Link <https://github.com/expectocode/telegram-export>`_ /
|
`telegram-export <https://github.com/expectocode/telegram-export>`_ /
|
||||||
`Author's website <https://github.com/expectocode>`_
|
`expectocode's GitHub <https://github.com/expectocode>`_
|
||||||
|
|
||||||
A tool to download Telegram data (users, chats, messages, and media)
|
A tool to download Telegram data (users, chats, messages, and media)
|
||||||
into a database (and display the saved data).
|
into a database (and display the saved data).
|
||||||
|
@ -37,28 +39,28 @@ into a database (and display the saved data).
|
||||||
.. _projects-mautrix-telegram:
|
.. _projects-mautrix-telegram:
|
||||||
|
|
||||||
mautrix-telegram
|
mautrix-telegram
|
||||||
****************
|
================
|
||||||
|
|
||||||
`Link <https://github.com/tulir/mautrix-telegram>`_ /
|
`mautrix-telegram <https://github.com/tulir/mautrix-telegram>`_ /
|
||||||
`Author's website <https://maunium.net/>`_
|
`maunium's site <https://maunium.net/>`_
|
||||||
|
|
||||||
A Matrix-Telegram hybrid puppeting/relaybot bridge.
|
A Matrix-Telegram hybrid puppeting/relaybot bridge.
|
||||||
|
|
||||||
.. _projects-telegramtui:
|
.. _projects-telegramtui:
|
||||||
|
|
||||||
TelegramTUI
|
TelegramTUI
|
||||||
***********
|
===========
|
||||||
|
|
||||||
`Link <https://github.com/bad-day/TelegramTUI>`_ /
|
`TelegramTUI <https://github.com/bad-day/TelegramTUI>`_ /
|
||||||
`Author's website <https://github.com/bad-day>`_
|
`bad-day's GitHub <https://github.com/bad-day>`_
|
||||||
|
|
||||||
A Telegram client on your terminal.
|
A Telegram client on your terminal.
|
||||||
|
|
||||||
spotify_telegram_bio_updater
|
spotify_telegram_bio_updater
|
||||||
****************************
|
============================
|
||||||
|
|
||||||
`Link <https://github.com/Poolitzer/spotify_telegram_bio_updater>`_ /
|
`spotify_telegram_bio_updater <https://github.com/Poolitzer/spotify_telegram_bio_updater>`_ /
|
||||||
`Author's website <https://t.me/pooltalks>`_
|
`pooltalks' Telegram <https://t.me/pooltalks>`_
|
||||||
|
|
||||||
Small project that updates the biography of a telegram user according
|
Small project that updates the biography of a telegram user according
|
||||||
to their current Spotify playback, or revert it if no playback is active.
|
to their current Spotify playback, or revert it if no playback is active.
|
|
@ -5,13 +5,13 @@ Users
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
These examples assume you have read :ref:`accessing-the-full-api`.
|
These examples assume you have read :ref:`full-api`.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
Retrieving full information
|
Retrieving full information
|
||||||
***************************
|
===========================
|
||||||
|
|
||||||
If you need to retrieve the bio, biography or about information for a user
|
If you need to retrieve the bio, biography or about information for a user
|
||||||
you should use :tl:`GetFullUser`:
|
you should use :tl:`GetFullUser`:
|
||||||
|
@ -32,7 +32,7 @@ See :tl:`UserFull` to know what other fields you can access.
|
||||||
|
|
||||||
|
|
||||||
Updating your name and/or bio
|
Updating your name and/or bio
|
||||||
*****************************
|
=============================
|
||||||
|
|
||||||
The first name, last name and bio (about) can all be changed with the same
|
The first name, last name and bio (about) can all be changed with the same
|
||||||
request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
|
request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
|
||||||
|
@ -47,7 +47,7 @@ request. Omitted fields won't change after invoking :tl:`UpdateProfile`:
|
||||||
|
|
||||||
|
|
||||||
Updating your username
|
Updating your username
|
||||||
**********************
|
======================
|
||||||
|
|
||||||
You need to use :tl:`account.UpdateUsername`:
|
You need to use :tl:`account.UpdateUsername`:
|
||||||
|
|
||||||
|
@ -59,7 +59,7 @@ You need to use :tl:`account.UpdateUsername`:
|
||||||
|
|
||||||
|
|
||||||
Updating your profile photo
|
Updating your profile photo
|
||||||
***************************
|
===========================
|
||||||
|
|
||||||
The easiest way is to upload a new file and use that as the profile photo
|
The easiest way is to upload a new file and use that as the profile photo
|
||||||
through :tl:`UploadProfilePhoto`:
|
through :tl:`UploadProfilePhoto`:
|
16
readthedocs/examples/word-of-warning.rst
Normal file
16
readthedocs/examples/word-of-warning.rst
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
=================
|
||||||
|
A Word of Warning
|
||||||
|
=================
|
||||||
|
|
||||||
|
Full API is **not** how you are intended to use the library. You **should**
|
||||||
|
always prefer the :ref:`client-ref`. However, not everything is implemented
|
||||||
|
as a friendly method, so full API is your last resort.
|
||||||
|
|
||||||
|
If you select a method in :ref:`client-ref`, you will most likely find an
|
||||||
|
example for that method. This is how you are intended to use the library.
|
||||||
|
|
||||||
|
Full API **will** break between different minor versions of the library,
|
||||||
|
since Telegram changes very often. The friendly methods will be kept
|
||||||
|
compatible between major versions.
|
||||||
|
|
||||||
|
If you need to see real-world examples, please refer to :ref:`telethon_projects`.
|
|
@ -5,13 +5,13 @@ Working with messages
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
These examples assume you have read :ref:`accessing-the-full-api`.
|
These examples assume you have read :ref:`full-api`.
|
||||||
|
|
||||||
.. contents::
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
Sending stickers
|
Sending stickers
|
||||||
****************
|
================
|
||||||
|
|
||||||
Stickers are nothing else than ``files``, and when you successfully retrieve
|
Stickers are nothing else than ``files``, and when you successfully retrieve
|
||||||
the stickers for a certain sticker set, all you will have are ``handles`` to
|
the stickers for a certain sticker set, all you will have are ``handles`` to
|
|
@ -1,343 +0,0 @@
|
||||||
.. _mastering-telethon:
|
|
||||||
|
|
||||||
==================
|
|
||||||
Mastering Telethon
|
|
||||||
==================
|
|
||||||
|
|
||||||
You've come far! In this section you will learn best practices, as well
|
|
||||||
as how to fix some silly (yet common) errors you may have found. Let's
|
|
||||||
start with a simple one.
|
|
||||||
|
|
||||||
Asyncio madness
|
|
||||||
***************
|
|
||||||
|
|
||||||
We promise ``asyncio`` is worth learning. Take your time to learn it.
|
|
||||||
It's a powerful tool that enables you to use this powerful library.
|
|
||||||
You need to be comfortable with it if you want to master Telethon.
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
AttributeError: 'coroutine' object has no attribute 'id'
|
|
||||||
|
|
||||||
You probably had a previous version, upgraded, and expected everything
|
|
||||||
to work. Remember, just add this line:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import telethon.sync
|
|
||||||
|
|
||||||
If you're inside an event handler you need to ``await`` **everything** that
|
|
||||||
*makes a network request*. Getting users, sending messages, and nearly
|
|
||||||
everything in the library needs access to the network, so they need to
|
|
||||||
be awaited:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
async def handler(event):
|
|
||||||
print((await event.get_sender()).username)
|
|
||||||
|
|
||||||
|
|
||||||
You may want to read https://lonamiwebs.github.io/blog/asyncio/ to help
|
|
||||||
you understand ``asyncio`` better. I'm open for `feedback
|
|
||||||
<https://t.me/LonamiWebs>`_ regarding that blog post
|
|
||||||
|
|
||||||
Entities
|
|
||||||
********
|
|
||||||
|
|
||||||
A lot of methods and requests require *entities* to work. For example,
|
|
||||||
you send a message to an *entity*, get the username of an *entity*, and
|
|
||||||
so on. There is an entire section on this at :ref:`entities` due to their
|
|
||||||
importance.
|
|
||||||
|
|
||||||
There are a lot of things that work as entities: usernames, phone numbers,
|
|
||||||
chat links, invite links, IDs, and the types themselves. That is, you can
|
|
||||||
use any of those when you see an "entity" is needed.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Remember that the phone number must be in your contact list before you
|
|
||||||
can use it.
|
|
||||||
|
|
||||||
You should use, **from better to worse**:
|
|
||||||
|
|
||||||
1. Input entities. For example, `event.input_chat
|
|
||||||
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`,
|
|
||||||
`message.input_sender
|
|
||||||
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`,
|
|
||||||
or caching an entity you will use a lot with
|
|
||||||
``entity = await client.get_input_entity(...)``.
|
|
||||||
|
|
||||||
2. Entities. For example, if you had to get someone's
|
|
||||||
username, you can just use ``user`` or ``channel``.
|
|
||||||
It will work. Only use this option if you already have the entity!
|
|
||||||
|
|
||||||
3. IDs. This will always look the entity up from the
|
|
||||||
cache (the ``*.session`` file caches seen entities).
|
|
||||||
|
|
||||||
4. Usernames, phone numbers and links. The cache will be
|
|
||||||
used too (unless you force a `client.get_entity()
|
|
||||||
<telethon.client.users.UserMethods.get_entity>`),
|
|
||||||
but may make a request if the username, phone or link
|
|
||||||
has not been found yet.
|
|
||||||
|
|
||||||
In short, unlike in most bot API libraries where you use the ID, you
|
|
||||||
**should not** use the ID *if* you have the input entity. This is OK:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def handler(event):
|
|
||||||
await client.send_message(event.sender_id, 'Hi')
|
|
||||||
|
|
||||||
However, **this is better**:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def handler(event):
|
|
||||||
await client.send_message(event.input_sender, 'Hi')
|
|
||||||
|
|
||||||
Note that this also works for `message <telethon.tl.custom.message.Message>`
|
|
||||||
instead of ``event``. Telegram may not send the sender information, so if you
|
|
||||||
want to be 99% confident that the above will work you should do this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def handler(event):
|
|
||||||
await client.send_message(await event.get_input_sender(), 'Hi')
|
|
||||||
|
|
||||||
Methods are able to make network requests to get information that
|
|
||||||
could be missing. Properties will never make a network request.
|
|
||||||
|
|
||||||
Of course, it is convenient to IDs or usernames for most purposes. It will
|
|
||||||
be fast enough and caching with `client.get_input_entity(...)
|
|
||||||
<telethon.client.users.UserMethods.get_input_entity>` will
|
|
||||||
be a micro-optimization. However it's worth knowing, and it
|
|
||||||
will also let you know if the entity cannot be found beforehand.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Sometimes Telegram doesn't send the access hash inside entities,
|
|
||||||
so using `chat <telethon.tl.custom.chatgetter.ChatGetter.chat>`
|
|
||||||
or `sender <telethon.tl.custom.sendergetter.SenderGetter.sender>`
|
|
||||||
may not work, but `input_chat
|
|
||||||
<telethon.tl.custom.chatgetter.ChatGetter.input_chat>`
|
|
||||||
and `input_sender
|
|
||||||
<telethon.tl.custom.sendergetter.SenderGetter.input_sender>`
|
|
||||||
while making requests definitely will since that's what they exist
|
|
||||||
for. If Telegram did not send information about the access hash,
|
|
||||||
you will get something like "Invalid channel object" or
|
|
||||||
"Invalid user object".
|
|
||||||
|
|
||||||
|
|
||||||
Debugging
|
|
||||||
*********
|
|
||||||
|
|
||||||
**Please enable logging**:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.WARNING)
|
|
||||||
|
|
||||||
Change it for ``logging.DEBUG`` if you are asked for logs. It will save you
|
|
||||||
a lot of headaches and time when you work with events. This is for errors.
|
|
||||||
|
|
||||||
Debugging is *really* important. Telegram's API is really big and there
|
|
||||||
is a lot of things that you should know. Such as, what attributes or fields
|
|
||||||
does a result have? Well, the easiest thing to do is printing it:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
user = client.get_entity('Lonami')
|
|
||||||
print(user)
|
|
||||||
|
|
||||||
That will show a huge line similar to the following:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
User(id=10885151, is_self=False, contact=False, mutual_contact=False, deleted=False, bot=False, bot_chat_history=False, bot_nochats=False, verified=False, restricted=False, min=False, bot_inline_geo=False, access_hash=123456789012345678, first_name='Lonami', last_name=None, username='Lonami', phone=None, photo=UserProfilePhoto(photo_id=123456789012345678, photo_small=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678), photo_big=FileLocation(dc_id=4, volume_id=1234567890, local_id=1234567890, secret=123456789012345678)), status=UserStatusOffline(was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)), bot_info_version=None, restriction_reason=None, bot_inline_placeholder=None, lang_code=None)
|
|
||||||
|
|
||||||
That's a lot of text. But as you can see, all the properties are there.
|
|
||||||
So if you want the username you **don't use regex** or anything like
|
|
||||||
splitting ``str(user)`` to get what you want. You just access the
|
|
||||||
attribute you need:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
username = user.username
|
|
||||||
|
|
||||||
Can we get better than the shown string, though? Yes!
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
print(user.stringify())
|
|
||||||
|
|
||||||
Will show a much better:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
User(
|
|
||||||
id=10885151,
|
|
||||||
is_self=False,
|
|
||||||
contact=False,
|
|
||||||
mutual_contact=False,
|
|
||||||
deleted=False,
|
|
||||||
bot=False,
|
|
||||||
bot_chat_history=False,
|
|
||||||
bot_nochats=False,
|
|
||||||
verified=False,
|
|
||||||
restricted=False,
|
|
||||||
min=False,
|
|
||||||
bot_inline_geo=False,
|
|
||||||
access_hash=123456789012345678,
|
|
||||||
first_name='Lonami',
|
|
||||||
last_name=None,
|
|
||||||
username='Lonami',
|
|
||||||
phone=None,
|
|
||||||
photo=UserProfilePhoto(
|
|
||||||
photo_id=123456789012345678,
|
|
||||||
photo_small=FileLocation(
|
|
||||||
dc_id=4,
|
|
||||||
volume_id=123456789,
|
|
||||||
local_id=123456789,
|
|
||||||
secret=-123456789012345678
|
|
||||||
),
|
|
||||||
photo_big=FileLocation(
|
|
||||||
dc_id=4,
|
|
||||||
volume_id=123456789,
|
|
||||||
local_id=123456789,
|
|
||||||
secret=123456789012345678
|
|
||||||
)
|
|
||||||
),
|
|
||||||
status=UserStatusOffline(
|
|
||||||
was_online=datetime.datetime(2018, 1, 2, 3, 4, 5, tzinfo=datetime.timezone.utc)
|
|
||||||
),
|
|
||||||
bot_info_version=None,
|
|
||||||
restriction_reason=None,
|
|
||||||
bot_inline_placeholder=None,
|
|
||||||
lang_code=None
|
|
||||||
)
|
|
||||||
|
|
||||||
Now it's easy to see how we could get, for example,
|
|
||||||
the ``was_online`` time. It's inside ``status``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
online_at = user.status.was_online
|
|
||||||
|
|
||||||
You don't need to print everything to see what all the possible values
|
|
||||||
can be. You can just search in http://lonamiwebs.github.io/Telethon/.
|
|
||||||
|
|
||||||
Remember that you can use Python's `isinstance
|
|
||||||
<https://docs.python.org/3/library/functions.html#isinstance>`_
|
|
||||||
to check the type of something. For example:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import types
|
|
||||||
|
|
||||||
if isinstance(user.status, types.UserStatusOffline):
|
|
||||||
print(user.status.was_online)
|
|
||||||
|
|
||||||
Avoiding Limits
|
|
||||||
***************
|
|
||||||
|
|
||||||
Don't spam. You won't get ``FloodWaitError`` or your account banned or
|
|
||||||
deleted if you use the library *for legit use cases*. Make cool tools.
|
|
||||||
Don't spam! Nobody knows the exact limits for all requests since they
|
|
||||||
depend on a lot of factors, so don't bother asking.
|
|
||||||
|
|
||||||
Still, if you do have a legit use case and still get those errors, the
|
|
||||||
library will automatically sleep when they are smaller than 60 seconds
|
|
||||||
by default. You can set different "auto-sleep" thresholds:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.flood_sleep_threshold = 0 # Don't auto-sleep
|
|
||||||
client.flood_sleep_threshold = 24 * 60 * 60 # Sleep always
|
|
||||||
|
|
||||||
You can also except it and act as you prefer:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.errors import FloodWaitError
|
|
||||||
try:
|
|
||||||
...
|
|
||||||
except FloodWaitError as e:
|
|
||||||
print('Flood waited for', e.seconds)
|
|
||||||
quit(1)
|
|
||||||
|
|
||||||
VoIP numbers are very limited, and some countries are more limited too.
|
|
||||||
|
|
||||||
Chat or User From Messages
|
|
||||||
**************************
|
|
||||||
|
|
||||||
Although it's explicitly noted in the documentation that messages
|
|
||||||
*subclass* `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
|
|
||||||
and `SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>`,
|
|
||||||
some people still don't get inheritance.
|
|
||||||
|
|
||||||
When the documentation says "Bases: `telethon.tl.custom.chatgetter.ChatGetter`"
|
|
||||||
it means that the class you're looking at, *also* can act as the class it
|
|
||||||
bases. In this case, `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`
|
|
||||||
knows how to get the *chat* where a thing belongs to.
|
|
||||||
|
|
||||||
So, a `Message <telethon.tl.custom.message.Message>` is a
|
|
||||||
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`.
|
|
||||||
That means you can do this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message.is_private
|
|
||||||
message.chat_id
|
|
||||||
message.get_chat()
|
|
||||||
# ...etc
|
|
||||||
|
|
||||||
`SenderGetter <telethon.tl.custom.sendergetter.SenderGetter>` is similar:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message.user_id
|
|
||||||
message.get_input_user()
|
|
||||||
message.user
|
|
||||||
# ...etc
|
|
||||||
|
|
||||||
Quite a few things implement them, so it makes sense to reuse the code.
|
|
||||||
For example, all events (except raw updates) implement `ChatGetter
|
|
||||||
<telethon.tl.custom.chatgetter.ChatGetter>` since all events occur
|
|
||||||
in some chat.
|
|
||||||
|
|
||||||
Session Files
|
|
||||||
*************
|
|
||||||
|
|
||||||
They are an important part for the library to be efficient, such as caching
|
|
||||||
and handling your authorization key (or you would have to login every time!).
|
|
||||||
|
|
||||||
However, some people have a lot of trouble with SQLite, especially in Windows:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
...some lines of traceback
|
|
||||||
'insert or replace into entities values (?,?,?,?,?)', rows)
|
|
||||||
sqlite3.OperationalError: database is locked
|
|
||||||
|
|
||||||
This error occurs when **two or more clients use the same session**,
|
|
||||||
that is, when you write the same session name to be used in the client:
|
|
||||||
|
|
||||||
* You have two scripts running (interactive sessions count too).
|
|
||||||
* You have two clients in the same script running at the same time.
|
|
||||||
|
|
||||||
The solution is, if you need two clients, use two sessions. If the
|
|
||||||
problem persists and you're on Linux, you can use ``fuser my.session``
|
|
||||||
to find out the process locking the file. As a last resort, you can
|
|
||||||
reboot your system.
|
|
||||||
|
|
||||||
If you really dislike SQLite, use a different session storage. There
|
|
||||||
is an entire section covering that at :ref:`sessions`.
|
|
||||||
|
|
||||||
Final Words
|
|
||||||
***********
|
|
||||||
|
|
||||||
Now you are aware of some common errors and use cases, this should help
|
|
||||||
you master your Telethon skills to get the most out of the library. Have
|
|
||||||
fun developing awesome things!
|
|
|
@ -1,73 +0,0 @@
|
||||||
.. _update-modes:
|
|
||||||
|
|
||||||
============
|
|
||||||
Update Modes
|
|
||||||
============
|
|
||||||
|
|
||||||
With ``asyncio``, the library has several tasks running in the background.
|
|
||||||
One task is used for sending requests, another task is used to receive them,
|
|
||||||
and a third one is used to handle updates.
|
|
||||||
|
|
||||||
To handle updates, you must keep your script running. You can do this in
|
|
||||||
several ways. For instance, if you are *not* running ``asyncio``'s event
|
|
||||||
loop, you should use `client.run_until_disconnected
|
|
||||||
<telethon.client.updates.UpdateMethods.run_until_disconnected>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from telethon import TelegramClient
|
|
||||||
|
|
||||||
client = TelegramClient(...)
|
|
||||||
...
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
|
|
||||||
Behind the scenes, this method is ``await``'ing on the `client.disconnected
|
|
||||||
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>` property,
|
|
||||||
so the code above and the following are equivalent:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
from telethon import TelegramClient
|
|
||||||
|
|
||||||
client = TelegramClient(...)
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await client.disconnected
|
|
||||||
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
|
|
||||||
You could also run `client.disconnected
|
|
||||||
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`
|
|
||||||
until it completed.
|
|
||||||
|
|
||||||
But if you don't want to ``await``, then you should know what you want
|
|
||||||
to be doing instead! What matters is that you shouldn't let your script
|
|
||||||
die. If you don't care about updates, you don't need any of this.
|
|
||||||
|
|
||||||
Notice that unlike `client.disconnected
|
|
||||||
<telethon.client.telegrambaseclient.TelegramBaseClient.disconnected>`,
|
|
||||||
`client.run_until_disconnected
|
|
||||||
<telethon.client.updates.UpdateMethods.run_until_disconnected>` will
|
|
||||||
handle ``KeyboardInterrupt`` with you. This method is special and can
|
|
||||||
also be ran while the loop is running, so you can do this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await client.run_until_disconnected()
|
|
||||||
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
|
|
||||||
If you need to process updates sequentially (i.e. not in parallel),
|
|
||||||
you should set ``sequential_updates=True`` when creating the client:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with TelegramClient(..., sequential_updates=True) as client:
|
|
||||||
...
|
|
|
@ -1,263 +0,0 @@
|
||||||
.. _creating-a-client:
|
|
||||||
|
|
||||||
=================
|
|
||||||
Creating a Client
|
|
||||||
=================
|
|
||||||
|
|
||||||
|
|
||||||
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.
|
|
||||||
|
|
||||||
2. Click under API Development tools.
|
|
||||||
|
|
||||||
3. A *Create new application* window will appear. Fill in your application
|
|
||||||
details. There is no need to enter any *URL*, and only the first two
|
|
||||||
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** 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``.
|
|
||||||
This class will be your main interface with Telegram's API, and creating
|
|
||||||
one is very simple:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, sync
|
|
||||||
|
|
||||||
# Use your own values here
|
|
||||||
api_id = 12345
|
|
||||||
api_hash = '0123456789abcdef0123456789abcdef'
|
|
||||||
|
|
||||||
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 by default a database file using Python's ``sqlite3``.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
It's important that the library always accesses the same session file so
|
|
||||||
that you don't need to re-send the code over and over again. By default it
|
|
||||||
creates the file in your working directory, but absolute paths work too.
|
|
||||||
|
|
||||||
|
|
||||||
Once you have a client ready, simply `.start()
|
|
||||||
<telethon.client.auth.AuthMethods.start>` it:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.start()
|
|
||||||
|
|
||||||
This line connects to Telegram, checks whether the current user is
|
|
||||||
authorized or not, and if it's not, it begins the login or sign up process.
|
|
||||||
|
|
||||||
When you're done with your code, you should always disconnect:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client = TelegramClient(...)
|
|
||||||
try:
|
|
||||||
client.start()
|
|
||||||
... # your code here
|
|
||||||
finally:
|
|
||||||
client.disconnect()
|
|
||||||
|
|
||||||
|
|
||||||
You can also use a ``with`` block to achieve the same effect:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client = TelegramClient(...)
|
|
||||||
with client:
|
|
||||||
... # your code here
|
|
||||||
|
|
||||||
# or
|
|
||||||
with TelegramClient(...) as client:
|
|
||||||
... # your code here
|
|
||||||
|
|
||||||
|
|
||||||
Wrapping it all together:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, sync
|
|
||||||
with TelegramClient('session_name', api_id, api_hash) as client:
|
|
||||||
... # your code
|
|
||||||
|
|
||||||
Just two setup lines.
|
|
||||||
|
|
||||||
.. warning::
|
|
||||||
Please note that if you fail to login around 5 times (or change the first
|
|
||||||
parameter of the :ref:`TelegramClient <telethon-client>`, which is the session
|
|
||||||
name) you will receive a ``FloodWaitError`` of around 22 hours, so be
|
|
||||||
careful not to mess this up! This shouldn't happen if you're doing things
|
|
||||||
as explained, though.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
If you want to use a **proxy**, you have to `install PySocks`__
|
|
||||||
(via pip or manual) and then set the appropriated parameters:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import socks
|
|
||||||
client = TelegramClient('session_id',
|
|
||||||
api_id=12345, api_hash='0123456789abcdef0123456789abcdef',
|
|
||||||
proxy=(socks.SOCKS5, 'localhost', 4444)
|
|
||||||
)
|
|
||||||
|
|
||||||
The ``proxy=`` argument should be a tuple, a list or a dict,
|
|
||||||
consisting of parameters described `here`__.
|
|
||||||
|
|
||||||
|
|
||||||
Manually Signing In
|
|
||||||
*******************
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Skip this unless you need more control when connecting.
|
|
||||||
|
|
||||||
If you need more control, you can replicate what `client.start()
|
|
||||||
<telethon.client.auth.AuthMethods.start>` is doing behind the scenes
|
|
||||||
for your convenience. The first step is to connect to the servers:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.connect()
|
|
||||||
|
|
||||||
You may or may not be authorized yet. You must be authorized
|
|
||||||
before you're able to send any request:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.is_user_authorized() # Returns True if you can send requests
|
|
||||||
|
|
||||||
If you're not authorized, you need to `.sign_in
|
|
||||||
<telethon.client.auth.AuthMethods.sign_in>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
phone_number = '+34600000000'
|
|
||||||
client.send_code_request(phone_number)
|
|
||||||
myself = client.sign_in(phone_number, input('Enter code: '))
|
|
||||||
# If .sign_in raises PhoneNumberUnoccupiedError, use .sign_up instead
|
|
||||||
# If .sign_in raises SessionPasswordNeeded error, call .sign_in(password=...)
|
|
||||||
# You can import both exceptions from telethon.errors.
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
If you send the code that Telegram sent you over the app through the
|
|
||||||
app itself, it will expire immediately. You can still send the code
|
|
||||||
through the app by "obfuscating" it (maybe add a magic constant, like
|
|
||||||
``12345``, and then subtract it to get the real code back) or any other
|
|
||||||
technique.
|
|
||||||
|
|
||||||
``myself`` is your Telegram user. You can view all the information about
|
|
||||||
yourself by doing ``print(myself.stringify())``. You're now ready to use
|
|
||||||
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
|
|
||||||
|
|
||||||
from telethon import TelegramClient, sync
|
|
||||||
client = TelegramClient('session_name', api_id, api_hash)
|
|
||||||
|
|
||||||
client.connect()
|
|
||||||
if not client.is_user_authorized():
|
|
||||||
client.send_code_request(phone_number)
|
|
||||||
me = client.sign_in(phone_number, input('Enter code: '))
|
|
||||||
|
|
||||||
|
|
||||||
Remember that this is the manual process and it's so much easier
|
|
||||||
to use the code snippets shown at the beginning of the page.
|
|
||||||
|
|
||||||
The code shown is just what `.start()
|
|
||||||
<telethon.client.auth.AuthMethods.start>` will be doing behind the scenes
|
|
||||||
(with a few extra checks), so that you know how to sign in case you want
|
|
||||||
to avoid using ``input()`` (the default) for whatever reason. If no phone
|
|
||||||
or bot token is provided, you will be asked one through ``input()``. The
|
|
||||||
method also accepts a ``phone=`` and ``bot_token`` parameters.
|
|
||||||
|
|
||||||
You can use either, as both will work. Determining which
|
|
||||||
is just a matter of taste, and how much control you need.
|
|
||||||
|
|
||||||
Remember that you can get yourself at any time with `client.get_me()
|
|
||||||
<telethon.client.users.UserMethods.get_me>`.
|
|
||||||
|
|
||||||
|
|
||||||
Two Factor Authorization (2FA)
|
|
||||||
------------------------------
|
|
||||||
|
|
||||||
If you have Two Factor Authorization (from now on, 2FA) enabled on your
|
|
||||||
account, calling `.sign_in()
|
|
||||||
<telethon.client.auth.AuthMethods.sign_in>` will raise a
|
|
||||||
``SessionPasswordNeededError``. When this happens, just use the method
|
|
||||||
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())
|
|
||||||
|
|
||||||
|
|
||||||
The mentioned `.start()
|
|
||||||
<telethon.client.auth.AuthMethods.start>` method will handle this for you as
|
|
||||||
well, but you must set the ``password=`` parameter beforehand (it won't be
|
|
||||||
asked).
|
|
||||||
|
|
||||||
If you don't have 2FA enabled, but you would like to do so through the
|
|
||||||
library, use `client.edit_2fa()
|
|
||||||
<telethon.client.auth.AuthMethods.edit_2fa>`.
|
|
||||||
|
|
||||||
Be sure to know what you're doing when using this function and
|
|
||||||
you won't run into any problems. Take note that if you want to
|
|
||||||
set only the email/hint and leave the current password unchanged,
|
|
||||||
you need to "redo" the 2fa.
|
|
||||||
|
|
||||||
See the examples below:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.errors import EmailUnconfirmedError
|
|
||||||
|
|
||||||
# Sets 2FA password for first time:
|
|
||||||
client.edit_2fa(new_password='supersecurepassword')
|
|
||||||
|
|
||||||
# Changes password:
|
|
||||||
client.edit_2fa(current_password='supersecurepassword',
|
|
||||||
new_password='changedmymind')
|
|
||||||
|
|
||||||
# Clears current password (i.e. removes 2FA):
|
|
||||||
client.edit_2fa(current_password='changedmymind', new_password=None)
|
|
||||||
|
|
||||||
# Sets new password with recovery email:
|
|
||||||
try:
|
|
||||||
client.edit_2fa(new_password='memes and dreams',
|
|
||||||
email='JohnSmith@example.com')
|
|
||||||
# Raises error (you need to check your email to complete 2FA setup.)
|
|
||||||
except EmailUnconfirmedError:
|
|
||||||
# You can put email checking code here if desired.
|
|
||||||
pass
|
|
||||||
|
|
||||||
# Also take note that unless you remove 2FA or explicitly
|
|
||||||
# give email parameter again it will keep the last used setting
|
|
||||||
|
|
||||||
# Set hint after already setting password:
|
|
||||||
client.edit_2fa(current_password='memes and dreams',
|
|
||||||
new_password='memes and dreams',
|
|
||||||
hint='It keeps you alive')
|
|
||||||
|
|
||||||
__ https://github.com/Anorov/PySocks#installation
|
|
||||||
__ https://github.com/Anorov/PySocks#usage-1
|
|
|
@ -1,95 +0,0 @@
|
||||||
.. _getting-started:
|
|
||||||
|
|
||||||
|
|
||||||
===============
|
|
||||||
Getting Started
|
|
||||||
===============
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
|
|
||||||
Simple Installation
|
|
||||||
*******************
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
**More details**: :ref:`installation`
|
|
||||||
|
|
||||||
|
|
||||||
Creating a client
|
|
||||||
*****************
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, sync
|
|
||||||
|
|
||||||
# These example values won't work. You must get your own api_id and
|
|
||||||
# api_hash from https://my.telegram.org, under API Development.
|
|
||||||
api_id = 12345
|
|
||||||
api_hash = '0123456789abcdef0123456789abcdef'
|
|
||||||
|
|
||||||
client = TelegramClient('session_name', api_id, api_hash).start()
|
|
||||||
|
|
||||||
**More details**: :ref:`creating-a-client`
|
|
||||||
|
|
||||||
|
|
||||||
Basic Usage
|
|
||||||
***********
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Getting information about yourself
|
|
||||||
me = client.get_me()
|
|
||||||
print(me.stringify())
|
|
||||||
|
|
||||||
# Sending a message (you can use 'me' or 'self' to message yourself)
|
|
||||||
client.send_message('username', 'Hello World from Telethon!')
|
|
||||||
|
|
||||||
# Sending a file
|
|
||||||
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
|
|
||||||
|
|
||||||
# Retrieving messages from a chat
|
|
||||||
from telethon import utils
|
|
||||||
for message in client.iter_messages('username', limit=10):
|
|
||||||
print(utils.get_display_name(message.sender), message.message)
|
|
||||||
|
|
||||||
# Listing all the dialogs (conversations you have open)
|
|
||||||
for dialog in client.get_dialogs(limit=10):
|
|
||||||
print(dialog.name, dialog.draft.text)
|
|
||||||
|
|
||||||
# Downloading profile photos (default path is the working directory)
|
|
||||||
client.download_profile_photo('username')
|
|
||||||
|
|
||||||
# Once you have a message with .media (if message.media)
|
|
||||||
# you can download it using client.download_media(),
|
|
||||||
# or even using message.download_media():
|
|
||||||
messages = client.get_messages('username')
|
|
||||||
messages[0].download_media()
|
|
||||||
|
|
||||||
**More details**: :ref:`telegram-client`
|
|
||||||
|
|
||||||
See :ref:`telethon-client` for all available friendly methods.
|
|
||||||
|
|
||||||
|
|
||||||
Handling Updates
|
|
||||||
****************
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import events
|
|
||||||
|
|
||||||
@client.on(events.NewMessage(incoming=True, pattern='(?i)hi'))
|
|
||||||
async def handler(event):
|
|
||||||
await event.reply('Hello!')
|
|
||||||
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
**More details**: :ref:`working-with-updates`
|
|
||||||
|
|
||||||
|
|
||||||
----------
|
|
||||||
|
|
||||||
You can continue by clicking on the "More details" link below each
|
|
||||||
snippet of code or the "Next" button at the bottom of the page.
|
|
|
@ -1,119 +0,0 @@
|
||||||
.. _installation:
|
|
||||||
|
|
||||||
============
|
|
||||||
Installation
|
|
||||||
============
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
|
|
||||||
Automatic Installation
|
|
||||||
**********************
|
|
||||||
|
|
||||||
To install Telethon, simply do:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
pip3 install telethon
|
|
||||||
|
|
||||||
Needless to say, you must have Python 3 and PyPi installed in your system.
|
|
||||||
See https://python.org and https://pypi.python.org/pypi/pip for more.
|
|
||||||
|
|
||||||
If you already have the library installed, upgrade with:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
pip3 install --upgrade telethon
|
|
||||||
|
|
||||||
You can also install the library directly from GitHub or a fork:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
# pip3 install git+https://github.com/LonamiWebs/Telethon.git
|
|
||||||
or
|
|
||||||
$ git clone https://github.com/LonamiWebs/Telethon.git
|
|
||||||
$ cd Telethon/
|
|
||||||
# pip install -Ue .
|
|
||||||
|
|
||||||
If you don't have root access, simply pass the ``--user`` flag to the pip
|
|
||||||
command. If you want to install a specific branch, append ``@branch`` to
|
|
||||||
the end of the first install command.
|
|
||||||
|
|
||||||
By default the library will use a pure Python implementation for encryption,
|
|
||||||
which can be really slow when uploading or downloading files. If you don't
|
|
||||||
mind using a C extension, install `cryptg <https://github.com/Lonami/cryptg>`__
|
|
||||||
via ``pip`` or as an extra:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
pip3 install telethon[cryptg]
|
|
||||||
|
|
||||||
|
|
||||||
Manual Installation
|
|
||||||
*******************
|
|
||||||
|
|
||||||
1. Install the required ``pyaes`` (`GitHub`__ | `PyPi`__) and
|
|
||||||
``rsa`` (`GitHub`__ | `PyPi`__) modules:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
pip3 install pyaes rsa
|
|
||||||
|
|
||||||
2. Clone Telethon's GitHub repository:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
git clone https://github.com/LonamiWebs/Telethon.git
|
|
||||||
|
|
||||||
3. Enter the cloned repository:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
cd Telethon
|
|
||||||
|
|
||||||
4. Run the code generator:
|
|
||||||
|
|
||||||
.. code-block:: sh
|
|
||||||
|
|
||||||
python3 setup.py gen
|
|
||||||
|
|
||||||
5. Done!
|
|
||||||
|
|
||||||
To generate the `method documentation`__, ``python3 setup.py gen docs``.
|
|
||||||
|
|
||||||
|
|
||||||
Optional dependencies
|
|
||||||
*********************
|
|
||||||
|
|
||||||
If pillow_ is installed, large images will be automatically resized when
|
|
||||||
sending photos to prevent Telegram from failing with "invalid image".
|
|
||||||
Official clients also do this.
|
|
||||||
|
|
||||||
If aiohttp_ is installed, the library will be able to download
|
|
||||||
:tl:`WebDocument` media files (otherwise you will get an error).
|
|
||||||
|
|
||||||
If hachoir_ is installed, it will be used to extract metadata from files
|
|
||||||
when sending documents. Telegram uses this information to show the song's
|
|
||||||
performer, artist, title, duration, and for videos too (including size).
|
|
||||||
Otherwise, they will default to empty values, and you can set the attributes
|
|
||||||
manually.
|
|
||||||
|
|
||||||
If cryptg_ is installed, encryption and decryption will be made in C instead
|
|
||||||
of Python which will be a lot faster. If your code deals with a lot of
|
|
||||||
updates or you are downloading/uploading a lot of files, you will notice
|
|
||||||
a considerable speed-up (from a hundred kilobytes per second to several
|
|
||||||
megabytes per second, if your connection allows it). If it's not installed,
|
|
||||||
pyaes_ will be used (which is pure Python, so it's much slower).
|
|
||||||
|
|
||||||
|
|
||||||
__ https://github.com/ricmoo/pyaes
|
|
||||||
__ https://pypi.python.org/pypi/pyaes
|
|
||||||
__ https://github.com/sybrenstuvel/python-rsa
|
|
||||||
__ https://pypi.python.org/pypi/rsa/3.4.2
|
|
||||||
__ https://lonamiwebs.github.io/Telethon
|
|
||||||
|
|
||||||
.. _pillow: https://python-pillow.org
|
|
||||||
.. _aiohttp: https://docs.aiohttp.org
|
|
||||||
.. _hachoir: https://hachoir.readthedocs.io
|
|
||||||
.. _cryptg: https://github.com/Lonami/cryptg
|
|
||||||
.. _pyaes: https://github.com/ricmoo/pyaes
|
|
|
@ -1,104 +0,0 @@
|
||||||
.. _telegram-client:
|
|
||||||
|
|
||||||
==============
|
|
||||||
TelegramClient
|
|
||||||
==============
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Make sure to use the friendly methods described in :ref:`telethon-client`!
|
|
||||||
This section is just an introduction to using the client, but all the
|
|
||||||
available methods are in the :ref:`telethon-client` reference, including
|
|
||||||
detailed descriptions to what they do.
|
|
||||||
|
|
||||||
The :ref:`TelegramClient <telethon-client>` 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 :ref:`TelegramClient <telethon-client>` 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
|
|
||||||
(assuming you have ``from telethon import sync`` or ``import telethon.sync``):
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
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 a 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,
|
|
||||||
but for now you don't need to worry about it. Simply know that they are
|
|
||||||
a good way to get information about a user, chat or channel.
|
|
||||||
|
|
||||||
Many other common methods for quick scripts are also available:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Note that you can use 'me' or 'self' to message yourself
|
|
||||||
client.send_message('username', 'Hello World from Telethon!')
|
|
||||||
|
|
||||||
# .send_message's parse mode defaults to markdown, so you
|
|
||||||
# can use **bold**, __italics__, [links](https://example.com), `code`,
|
|
||||||
# and even [mentions](@username)/[mentions](tg://user?id=123456789)
|
|
||||||
client.send_message('username', '**Using** __markdown__ `too`!')
|
|
||||||
|
|
||||||
client.send_file('username', '/home/myself/Pictures/holidays.jpg')
|
|
||||||
|
|
||||||
# The utils package has some goodies, like .get_display_name()
|
|
||||||
from telethon import utils
|
|
||||||
for message in client.iter_messages('username', limit=10):
|
|
||||||
print(utils.get_display_name(message.sender), message.message)
|
|
||||||
|
|
||||||
# Dialogs are the conversations you have open
|
|
||||||
for dialog in client.get_dialogs(limit=10):
|
|
||||||
print(dialog.name, dialog.draft.text)
|
|
||||||
|
|
||||||
# Default path is the working directory
|
|
||||||
client.download_profile_photo('username')
|
|
||||||
|
|
||||||
# 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
|
|
||||||
*****************
|
|
||||||
|
|
||||||
The :ref:`reference <telethon-package>` lists all the "handy" methods
|
|
||||||
available for you to use in the :ref:`TelegramClient <telethon-client>` 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.
|
|
||||||
|
|
||||||
See the mentioned :ref:`telethon-client` to find the available methods.
|
|
||||||
|
|
||||||
.. _InteractiveTelegramClient: https://github.com/LonamiWebs/Telethon/blob/master/telethon_examples/interactive_telegram_client.py
|
|
||||||
.. _TelegramClient: https://github.com/LonamiWebs/Telethon/tree/master/telethon/client
|
|
|
@ -1,333 +0,0 @@
|
||||||
.. _working-with-updates:
|
|
||||||
|
|
||||||
====================
|
|
||||||
Working with Updates
|
|
||||||
====================
|
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
Coming from Telethon before it reached its version 1.0?
|
|
||||||
Make sure to read :ref:`compatibility-and-convenience`!
|
|
||||||
Otherwise, you can ignore this note and just follow along.
|
|
||||||
|
|
||||||
The library comes with the `telethon.events` module. *Events* are an abstraction
|
|
||||||
over what Telegram calls `updates`__, and are meant to ease simple and common
|
|
||||||
usage when dealing with them, since there are many updates. If you're looking
|
|
||||||
for the method reference, check :ref:`telethon-events-package`, otherwise,
|
|
||||||
let's dive in!
|
|
||||||
|
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
The library logs by default no output, and any exception that occurs
|
|
||||||
inside your handlers will be "hidden" from you to prevent the thread
|
|
||||||
from terminating (so it can still deliver events). You should enable
|
|
||||||
logging when working with events, at least the error level, to see if
|
|
||||||
this is happening so you can debug the error.
|
|
||||||
|
|
||||||
**When using updates, please enable logging:**
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.ERROR)
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
|
|
||||||
Getting Started
|
|
||||||
***************
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, events
|
|
||||||
|
|
||||||
client = TelegramClient('name', api_id, api_hash)
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
async def my_event_handler(event):
|
|
||||||
if 'hello' in event.raw_text:
|
|
||||||
await event.reply('hi!')
|
|
||||||
|
|
||||||
client.start()
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
|
|
||||||
Not much, but there might be some things unclear. What does this code do?
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, events
|
|
||||||
|
|
||||||
client = TelegramClient('name', api_id, api_hash)
|
|
||||||
|
|
||||||
|
|
||||||
This is normal creation (of course, pass session name, API ID and hash).
|
|
||||||
Nothing we don't know already.
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
|
|
||||||
|
|
||||||
This Python decorator will attach itself to the ``my_event_handler``
|
|
||||||
definition, and basically means that *on* a `NewMessage
|
|
||||||
<telethon.events.newmessage.NewMessage>` *event*,
|
|
||||||
the callback function you're about to define will be called:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def my_event_handler(event):
|
|
||||||
if 'hello' in event.raw_text:
|
|
||||||
await event.reply('hi!')
|
|
||||||
|
|
||||||
|
|
||||||
If a `NewMessage
|
|
||||||
<telethon.events.newmessage.NewMessage>` event occurs,
|
|
||||||
and ``'hello'`` is in the text of the message, we `.reply()
|
|
||||||
<telethon.tl.custom.message.Message.reply>` to the event
|
|
||||||
with a ``'hi!'`` message.
|
|
||||||
|
|
||||||
Do you notice anything different? Yes! Event handlers **must** be ``async``
|
|
||||||
for them to work, and **every method using the network** needs to have an
|
|
||||||
``await``, otherwise, Python's ``asyncio`` will tell you that you forgot
|
|
||||||
to do so, so you can easily add it.
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.start()
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
|
|
||||||
Finally, this tells the client that we're done with our code. We run the
|
|
||||||
``asyncio`` loop until the client starts (this is done behind the scenes,
|
|
||||||
since the method is so common), and then we run it again until we are
|
|
||||||
disconnected. Of course, you can do other things instead of running
|
|
||||||
until disconnected. For this refer to :ref:`update-modes`.
|
|
||||||
|
|
||||||
|
|
||||||
More on events
|
|
||||||
**************
|
|
||||||
|
|
||||||
The `NewMessage <telethon.events.newmessage.NewMessage>` event has much
|
|
||||||
more than what was shown. You can access the `.sender
|
|
||||||
<telethon.tl.custom.message.Message.sender>` of the message
|
|
||||||
through that member, or even see if the message had `.media
|
|
||||||
<telethon.tl.custom.message.Message.media>`, a `.photo
|
|
||||||
<telethon.tl.custom.message.Message.photo>` or a `.document
|
|
||||||
<telethon.tl.custom.message.Message.document>` (which you
|
|
||||||
could download with for example `client.download_media(event.photo)
|
|
||||||
<telethon.client.downloads.DownloadMethods.download_media>`.
|
|
||||||
|
|
||||||
If you don't want to `.reply()
|
|
||||||
<telethon.tl.custom.message.Message.reply>` as a reply,
|
|
||||||
you can use the `.respond() <telethon.tl.custom.message.Message.respond>`
|
|
||||||
method instead. Of course, there are more events such as `ChatAction
|
|
||||||
<telethon.events.chataction.ChatAction>` or `UserUpdate
|
|
||||||
<telethon.events.userupdate.UserUpdate>`, and they're all
|
|
||||||
used in the same way. Simply add the `@client.on(events.XYZ)
|
|
||||||
<telethon.client.updates.UpdateMethods.on>` decorator on the top
|
|
||||||
of your handler and you're done! The event that will be passed always
|
|
||||||
is of type ``XYZ.Event`` (for instance, `NewMessage.Event
|
|
||||||
<telethon.events.newmessage.NewMessage.Event>`), except for the `Raw
|
|
||||||
<telethon.events.raw.Raw>` event which just passes the :tl:`Update` object.
|
|
||||||
|
|
||||||
Note that `.reply()
|
|
||||||
<telethon.tl.custom.message.Message.reply>` and `.respond()
|
|
||||||
<telethon.tl.custom.message.Message.respond>` are just wrappers around the
|
|
||||||
`client.send_message() <telethon.client.messages.MessageMethods.send_message>`
|
|
||||||
method which supports the ``file=`` parameter.
|
|
||||||
This means you can reply with a photo if you do `event.reply(file=photo)
|
|
||||||
<telethon.tl.custom.message.Message.reply>`.
|
|
||||||
|
|
||||||
You can put the same event on many handlers, and even different events on
|
|
||||||
the same handler. You can also have a handler work on only specific chats,
|
|
||||||
for example:
|
|
||||||
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import ast
|
|
||||||
import random
|
|
||||||
|
|
||||||
|
|
||||||
# Either a single item or a list of them will work for the chats.
|
|
||||||
# You can also use the IDs, Peers, or even User/Chat/Channel objects.
|
|
||||||
@client.on(events.NewMessage(chats=('TelethonChat', 'TelethonOffTopic')))
|
|
||||||
async def normal_handler(event):
|
|
||||||
if 'roll' in event.raw_text:
|
|
||||||
await event.reply(str(random.randint(1, 6)))
|
|
||||||
|
|
||||||
|
|
||||||
# Similarly, you can use incoming=True for messages that you receive
|
|
||||||
@client.on(events.NewMessage(chats='TelethonOffTopic', outgoing=True,
|
|
||||||
pattern='eval (.+)'))
|
|
||||||
async def admin_handler(event):
|
|
||||||
expression = event.pattern_match.group(1)
|
|
||||||
await event.reply(str(ast.literal_eval(expression)))
|
|
||||||
|
|
||||||
|
|
||||||
You can pass one or more chats to the ``chats`` parameter (as a list or tuple),
|
|
||||||
and only events from there will be processed. You can also specify whether you
|
|
||||||
want to handle incoming or outgoing messages (those you receive or those you
|
|
||||||
send). In this example, people can say ``'roll'`` and you will reply with a
|
|
||||||
random number, while if you say ``'eval 4+4'``, you will reply with the
|
|
||||||
solution. Try it!
|
|
||||||
|
|
||||||
|
|
||||||
Properties vs. Methods
|
|
||||||
**********************
|
|
||||||
|
|
||||||
The event shown above acts just like a `custom.Message
|
|
||||||
<telethon.tl.custom.message.Message>`, which means you
|
|
||||||
can access all the properties it has, like ``.sender``.
|
|
||||||
|
|
||||||
**However** events are different to other methods in the client, like
|
|
||||||
`client.get_messages <telethon.client.messages.MessageMethods.get_messages>`.
|
|
||||||
Events *may not* send information about the sender or chat, which means it
|
|
||||||
can be ``None``, but all the methods defined in the client always have this
|
|
||||||
information so it doesn't need to be re-fetched. For this reason, you have
|
|
||||||
``get_`` methods, which will make a network call if necessary.
|
|
||||||
|
|
||||||
In short, you should do this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
async def handler(event):
|
|
||||||
# event.input_chat may be None, use event.get_input_chat()
|
|
||||||
chat = await event.get_input_chat()
|
|
||||||
sender = await event.get_sender()
|
|
||||||
buttons = await event.get_buttons()
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
async for message in client.iter_messages('me', 10):
|
|
||||||
# Methods from the client always have these properties ready
|
|
||||||
chat = message.input_chat
|
|
||||||
sender = message.sender
|
|
||||||
buttons = message.buttons
|
|
||||||
|
|
||||||
Notice, properties (`message.sender
|
|
||||||
<telethon.tl.custom.message.Message.sender>`) don't need an ``await``, but
|
|
||||||
methods (`message.get_sender
|
|
||||||
<telethon.tl.custom.message.Message.get_sender>`) **do** need an ``await``,
|
|
||||||
and you should use methods in events for these properties that may need network.
|
|
||||||
|
|
||||||
|
|
||||||
Events Without the client
|
|
||||||
*************************
|
|
||||||
|
|
||||||
The code of your application starts getting big, so you decide to
|
|
||||||
separate the handlers into different files. But how can you access
|
|
||||||
the client from these files? You don't need to! Just `events.register
|
|
||||||
<telethon.events.register>` them:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# handlers/welcome.py
|
|
||||||
from telethon import events
|
|
||||||
|
|
||||||
@events.register(events.NewMessage('(?i)hello'))
|
|
||||||
async def handler(event):
|
|
||||||
client = event.client
|
|
||||||
await event.respond('Hey!')
|
|
||||||
await client.send_message('me', 'I said hello to someone')
|
|
||||||
|
|
||||||
|
|
||||||
Registering events is a way of saying "this method is an event handler".
|
|
||||||
You can use `telethon.events.is_handler` to check if any method is a handler.
|
|
||||||
You can think of them as a different approach to Flask's blueprints.
|
|
||||||
|
|
||||||
It's important to note that this does **not** add the handler to any client!
|
|
||||||
You never specified the client on which the handler should be used. You only
|
|
||||||
declared that it is a handler, and its type.
|
|
||||||
|
|
||||||
To actually use the handler, you need to `client.add_event_handler
|
|
||||||
<telethon.client.updates.UpdateMethods.add_event_handler>` to the
|
|
||||||
client (or clients) where they should be added to:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# main.py
|
|
||||||
from telethon import TelegramClient
|
|
||||||
import handlers.welcome
|
|
||||||
|
|
||||||
with TelegramClient(...) as client:
|
|
||||||
client.add_event_handler(handlers.welcome.handler)
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
|
|
||||||
This also means that you can register an event handler once and
|
|
||||||
then add it to many clients without re-declaring the event.
|
|
||||||
|
|
||||||
|
|
||||||
Events Without Decorators
|
|
||||||
*************************
|
|
||||||
|
|
||||||
If for any reason you don't want to use `telethon.events.register`,
|
|
||||||
you can explicitly pass the event handler to use to the mentioned
|
|
||||||
`client.add_event_handler
|
|
||||||
<telethon.client.updates.UpdateMethods.add_event_handler>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import TelegramClient, events
|
|
||||||
|
|
||||||
async def handler(event):
|
|
||||||
...
|
|
||||||
|
|
||||||
with TelegramClient(...) as client:
|
|
||||||
client.add_event_handler(handler, events.NewMessage)
|
|
||||||
client.run_until_disconnected()
|
|
||||||
|
|
||||||
|
|
||||||
Similarly, you also have `client.remove_event_handler
|
|
||||||
<telethon.client.updates.UpdateMethods.remove_event_handler>`
|
|
||||||
and `client.list_event_handlers
|
|
||||||
<telethon.client.updates.UpdateMethods.list_event_handlers>`.
|
|
||||||
|
|
||||||
The ``event`` argument is optional in all three methods and defaults to
|
|
||||||
`events.Raw <telethon.events.raw.Raw>` for adding, and ``None`` when
|
|
||||||
removing (so all callbacks would be removed).
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
The ``event`` type is ignored in `client.add_event_handler
|
|
||||||
<telethon.client.updates.UpdateMethods.add_event_handler>`
|
|
||||||
if you have used `telethon.events.register` on the ``callback``
|
|
||||||
before, since that's the point of using such method at all.
|
|
||||||
|
|
||||||
|
|
||||||
Stopping Propagation of Updates
|
|
||||||
*******************************
|
|
||||||
|
|
||||||
There might be cases when an event handler is supposed to be used solitary and
|
|
||||||
it makes no sense to process any other handlers in the chain. For this case,
|
|
||||||
it is possible to raise a `telethon.events.StopPropagation` exception which
|
|
||||||
will cause the propagation of the update through your handlers to stop:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.events import StopPropagation
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
async def _(event):
|
|
||||||
# ... some conditions
|
|
||||||
await event.delete()
|
|
||||||
|
|
||||||
# Other handlers won't have an event to work with
|
|
||||||
raise StopPropagation
|
|
||||||
|
|
||||||
@client.on(events.NewMessage)
|
|
||||||
async def _(event):
|
|
||||||
# Will never be reached, because it is the second handler
|
|
||||||
# in the chain.
|
|
||||||
pass
|
|
||||||
|
|
||||||
|
|
||||||
Remember to check :ref:`telethon-events-package` if you're looking for
|
|
||||||
the methods reference.
|
|
||||||
|
|
||||||
|
|
||||||
__ https://lonamiwebs.github.io/Telethon/types/update.html
|
|
|
@ -1,751 +0,0 @@
|
||||||
.. _telegram-client-example:
|
|
||||||
|
|
||||||
|
|
||||||
========================
|
|
||||||
Examples with the Client
|
|
||||||
========================
|
|
||||||
|
|
||||||
This section explores the methods defined in the :ref:`telegram-client`
|
|
||||||
with some practical examples. The section assumes that you have imported
|
|
||||||
the ``telethon.sync`` package and that you have a client ready to use.
|
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
There are some very common errors (such as forgetting to add
|
|
||||||
``import telethon.sync``) for newcomers to ``asyncio``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# AttributeError: 'coroutine' object has no attribute 'first_name'
|
|
||||||
print(client.get_me().first_name)
|
|
||||||
|
|
||||||
# TypeError: 'AsyncGenerator' object is not iterable
|
|
||||||
for message in client.iter_messages('me'):
|
|
||||||
...
|
|
||||||
|
|
||||||
# RuntimeError: This event loop is already running
|
|
||||||
with client.conversation('me') as conv:
|
|
||||||
...
|
|
||||||
|
|
||||||
That error means you're probably inside an ``async def`` so you
|
|
||||||
need to use:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
print((await client.get_me()).first_name)
|
|
||||||
async for message in client.iter_messages('me'):
|
|
||||||
...
|
|
||||||
|
|
||||||
async with client.conversation('me') as conv:
|
|
||||||
...
|
|
||||||
|
|
||||||
You can of course call other ``def`` functions from your ``async def``
|
|
||||||
event handlers, but if they need making API calls, make your own
|
|
||||||
functions ``async def`` so you can ``await`` things:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
async def helper(client):
|
|
||||||
await client.send_message('me', 'Hi')
|
|
||||||
|
|
||||||
If you're not inside an ``async def`` you can enter one like so:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
loop.run_until_complete(my_async_def())
|
|
||||||
|
|
||||||
|
|
||||||
.. contents::
|
|
||||||
|
|
||||||
|
|
||||||
Authorization
|
|
||||||
*************
|
|
||||||
|
|
||||||
Starting the client is as easy as calling `client.start()
|
|
||||||
<telethon.client.auth.AuthMethods.start>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.start()
|
|
||||||
... # code using the client
|
|
||||||
client.disconnect()
|
|
||||||
|
|
||||||
And you can even use a ``with`` block:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with client:
|
|
||||||
... # code using the client
|
|
||||||
|
|
||||||
|
|
||||||
.. note::
|
|
||||||
|
|
||||||
Remember we assume you have ``import telethon.sync``. You can of course
|
|
||||||
use the library without importing it. The code would be rewritten as:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
import asyncio
|
|
||||||
loop = asyncio.get_event_loop()
|
|
||||||
|
|
||||||
async def main():
|
|
||||||
await client.start()
|
|
||||||
...
|
|
||||||
await client.disconnect()
|
|
||||||
|
|
||||||
# or
|
|
||||||
async with client:
|
|
||||||
...
|
|
||||||
|
|
||||||
loop.run_until_complete(main())
|
|
||||||
|
|
||||||
All methods that need access to the network (e.g. to make an API call)
|
|
||||||
**must** be awaited (or their equivalent such as ``async for`` and
|
|
||||||
``async with``). You can do this yourself or you can let the library
|
|
||||||
do it for you by using ``import telethon.sync``. With event handlers,
|
|
||||||
you must do this yourself.
|
|
||||||
|
|
||||||
The cleanest way to delete your ``*.session`` file is `client.log_out
|
|
||||||
<telethon.client.auth.AuthMethods.log_out>`. Note that you will obviously
|
|
||||||
need to login again if you use this:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Logs out and deletes the session file; you will need to sign in again
|
|
||||||
client.log_out()
|
|
||||||
|
|
||||||
# You often simply want to disconnect. You will not need to sign in again
|
|
||||||
client.disconnect()
|
|
||||||
|
|
||||||
|
|
||||||
Group Chats
|
|
||||||
***********
|
|
||||||
|
|
||||||
You can easily iterate over all the :tl:`User` in a chat and
|
|
||||||
do anything you want with them by using `client.iter_participants
|
|
||||||
<telethon.client.chats.ChatMethods.iter_participants>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for user in client.iter_participants(chat):
|
|
||||||
... # do something with the user
|
|
||||||
|
|
||||||
You can also search by their name:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for user in client.iter_participants(chat, search='name'):
|
|
||||||
...
|
|
||||||
|
|
||||||
Or by their type (e.g. if they are admin) with :tl:`ChannelParticipantsFilter`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.types import ChannelParticipantsAdmins
|
|
||||||
|
|
||||||
for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
|
|
||||||
...
|
|
||||||
|
|
||||||
|
|
||||||
Open Conversations and Joined Channels
|
|
||||||
**************************************
|
|
||||||
|
|
||||||
The conversations you have open and the channels you have joined
|
|
||||||
are in your "dialogs", so to get them you need to `client.get_dialogs
|
|
||||||
<telethon.client.dialogs.DialogMethods.get_dialogs>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
dialogs = client.get_dialogs()
|
|
||||||
first = dialogs[0]
|
|
||||||
print(first.title)
|
|
||||||
|
|
||||||
You can then use the dialog as if it were a peer:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message(first, 'hi')
|
|
||||||
|
|
||||||
|
|
||||||
You can access `dialog.draft <telethon.tl.custom.draft.Draft>` or you can
|
|
||||||
get them all at once without getting the dialogs:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
drafts = client.get_drafts()
|
|
||||||
|
|
||||||
|
|
||||||
Downloading Media
|
|
||||||
*****************
|
|
||||||
|
|
||||||
It's easy to `download_profile_photo
|
|
||||||
<telethon.client.downloads.DownloadMethods.download_profile_photo>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.download_profile_photo(user)
|
|
||||||
|
|
||||||
Or `download_media <telethon.client.downloads.DownloadMethods.download_media>`
|
|
||||||
from a message:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.download_media(message)
|
|
||||||
client.download_media(message, filename)
|
|
||||||
# or
|
|
||||||
message.download_media()
|
|
||||||
message.download_media(filename)
|
|
||||||
|
|
||||||
Remember that these methods return the final filename where the
|
|
||||||
media was downloaded (e.g. it may add the extension automatically).
|
|
||||||
|
|
||||||
Getting Messages
|
|
||||||
****************
|
|
||||||
|
|
||||||
You can easily iterate over all the `messages
|
|
||||||
<telethon.tl.custom.message.Message>` of a chat with `iter_messages
|
|
||||||
<telethon.client.messages.MessageMethods.iter_messages>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for message in client.iter_messages(chat):
|
|
||||||
... # do something with the message from recent to older
|
|
||||||
|
|
||||||
for message in client.iter_messages(chat, reverse=True):
|
|
||||||
... # going from the oldest to the most recent
|
|
||||||
|
|
||||||
You can also use it to search for messages from a specific person:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for message in client.iter_messages(chat, from_user='me'):
|
|
||||||
...
|
|
||||||
|
|
||||||
Or you can search by text:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for message in client.iter_messages(chat, search='hello'):
|
|
||||||
...
|
|
||||||
|
|
||||||
Or you can search by media with a :tl:`MessagesFilter`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon.tl.types import InputMessagesFilterPhotos
|
|
||||||
|
|
||||||
for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
|
|
||||||
...
|
|
||||||
|
|
||||||
If you want a list instead, use the get variant. The second
|
|
||||||
argument is the limit, and ``None`` means "get them all":
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
|
|
||||||
from telethon.tl.types import InputMessagesFilterPhotos
|
|
||||||
|
|
||||||
# Get 0 photos and print the total
|
|
||||||
photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
|
|
||||||
print(photos.total)
|
|
||||||
|
|
||||||
# Get all the photos
|
|
||||||
photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
|
|
||||||
|
|
||||||
Or just some IDs:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message_1337 = client.get_messages(chats, ids=1337)
|
|
||||||
|
|
||||||
|
|
||||||
Exporting Messages
|
|
||||||
******************
|
|
||||||
|
|
||||||
If you plan on exporting data from your Telegram account, such as the entire
|
|
||||||
message history from your private conversations, chats or channels, or if you
|
|
||||||
plan to download a lot of media, you may prefer to do this within a *takeout*
|
|
||||||
session. Takeout sessions let you export data from your account with lower
|
|
||||||
flood wait limits.
|
|
||||||
|
|
||||||
To start a takeout session, simply call `client.takeout()
|
|
||||||
<telethon.client.account.AccountMethods.takeout>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import errors
|
|
||||||
|
|
||||||
try:
|
|
||||||
with client.takeout() as takeout:
|
|
||||||
for message in takeout.iter_messages(chat, wait_time=0):
|
|
||||||
... # Do something with the message
|
|
||||||
|
|
||||||
except errors.TakeoutInitDelayError as e:
|
|
||||||
print('Must wait', e.seconds, 'before takeout')
|
|
||||||
|
|
||||||
|
|
||||||
Depending on the condition of the session (for example, when it's very
|
|
||||||
young and the method has not been called before), you may or not need
|
|
||||||
to ``except errors.TakeoutInitDelayError``. However, it is good practice.
|
|
||||||
|
|
||||||
|
|
||||||
Sending Messages
|
|
||||||
****************
|
|
||||||
|
|
||||||
Just use `send_message <telethon.client.messages.MessageMethods.send_message>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message('lonami', 'Thanks for the Telethon library!')
|
|
||||||
|
|
||||||
The function returns the `custom.Message <telethon.tl.custom.message.Message>`
|
|
||||||
that was sent so you can do more things with it if you want.
|
|
||||||
|
|
||||||
You can also `reply <telethon.tl.custom.message.Message.reply>` or
|
|
||||||
`respond <telethon.tl.custom.message.Message.respond>` to messages:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message.reply('Hello')
|
|
||||||
message.respond('World')
|
|
||||||
|
|
||||||
Sending Markdown or HTML messages
|
|
||||||
*********************************
|
|
||||||
|
|
||||||
Markdown (``'md'`` or ``'markdown'``) is the default `parse_mode
|
|
||||||
<telethon.client.messageparse.MessageParseMethods.parse_mode>`
|
|
||||||
for the client. You can change the default parse mode like so:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.parse_mode = 'html'
|
|
||||||
|
|
||||||
|
|
||||||
Now all messages will be formatted as HTML by default:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message('me', 'Some <b>bold</b> and <i>italic</i> text')
|
|
||||||
client.send_message('me', 'An <a href="https://example.com">URL</a>')
|
|
||||||
client.send_message('me', '<code>code</code> and <pre>pre\nblocks</pre>')
|
|
||||||
client.send_message('me', '<a href="tg://user?id=me">Mentions</a>')
|
|
||||||
|
|
||||||
|
|
||||||
You can override the default parse mode to use for special cases:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# No parse mode by default
|
|
||||||
client.parse_mode = None
|
|
||||||
|
|
||||||
# ...but here I want markdown
|
|
||||||
client.send_message('me', 'Hello, **world**!', parse_mode='md')
|
|
||||||
|
|
||||||
# ...and here I need HTML
|
|
||||||
client.send_message('me', 'Hello, <i>world</i>!', parse_mode='html')
|
|
||||||
|
|
||||||
The rules are the same as for Bot API, so please refer to
|
|
||||||
https://core.telegram.org/bots/api#formatting-options.
|
|
||||||
|
|
||||||
Sending Messages with Media
|
|
||||||
***************************
|
|
||||||
|
|
||||||
Sending media can be done with `send_file
|
|
||||||
<telethon.client.uploads.UploadMethods.send_file>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
|
|
||||||
# or
|
|
||||||
client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
|
|
||||||
|
|
||||||
You can send voice notes or round videos by setting the right arguments:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
|
|
||||||
client.send_file(chat, '/my/videos/video.mp4', video_note=True)
|
|
||||||
|
|
||||||
You can set a JPG thumbnail for any document:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
|
|
||||||
|
|
||||||
You can force sending images as documents:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(chat, '/my/photos/photo.png', force_document=True)
|
|
||||||
|
|
||||||
You can send albums if you pass more than one file:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(chat, [
|
|
||||||
'/my/photos/holiday1.jpg',
|
|
||||||
'/my/photos/holiday2.jpg',
|
|
||||||
'/my/drawings/portrait.png'
|
|
||||||
])
|
|
||||||
|
|
||||||
The caption can also be a list to match the different photos.
|
|
||||||
|
|
||||||
Reusing Uploaded Files
|
|
||||||
**********************
|
|
||||||
|
|
||||||
All files you send are automatically cached, so if you do:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(first_chat, 'document.txt')
|
|
||||||
client.send_file(second_chat, 'document.txt')
|
|
||||||
|
|
||||||
The ``'document.txt'`` file will only be uploaded once. You
|
|
||||||
can disable this behaviour by settings ``allow_cache=False``:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_file(first_chat, 'document.txt', allow_cache=False)
|
|
||||||
client.send_file(second_chat, 'document.txt', allow_cache=False)
|
|
||||||
|
|
||||||
Disabling cache is the only way to send the same document with different
|
|
||||||
attributes (for example, you send an ``.ogg`` as a song but now you want
|
|
||||||
it to show as a voice note; you probably need to disable the cache).
|
|
||||||
|
|
||||||
However, you can *upload* the file once (not sending it yet!), and *then*
|
|
||||||
you can send it with different attributes. This means you can send an image
|
|
||||||
as a photo and a document:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
file = client.upload_file('photo.jpg')
|
|
||||||
client.send_file(chat, file) # sends as photo
|
|
||||||
client.send_file(chat, file, force_document=True) # sends as document
|
|
||||||
|
|
||||||
file.name = 'not a photo.jpg'
|
|
||||||
client.send_file(chat, file, force_document=True) # document, new name
|
|
||||||
|
|
||||||
Or, the example described before:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
file = client.upload_file('song.ogg')
|
|
||||||
client.send_file(chat, file) # sends as song
|
|
||||||
client.send_file(chat, file, voice_note=True) # sends as voice note
|
|
||||||
|
|
||||||
The ``file`` returned by `client.upload_file
|
|
||||||
<telethon.client.uploads.UploadMethods.upload_file>` represents the uploaded
|
|
||||||
file, not an immutable document (that's why the attributes can change, because
|
|
||||||
they are set later). This handle can be used only for a limited amount of time
|
|
||||||
(somewhere within a day). Telegram decides this limit and it is not public.
|
|
||||||
However, a day is often more than enough.
|
|
||||||
|
|
||||||
|
|
||||||
Sending Messages with Buttons
|
|
||||||
*****************************
|
|
||||||
|
|
||||||
**You must sign in as a bot** in order to add inline buttons (or normal
|
|
||||||
keyboards) to your messages. Once you have signed in as a bot specify
|
|
||||||
the `Button <telethon.tl.custom.button.Button>` or buttons to use:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import events
|
|
||||||
from telethon.tl.custom import Button
|
|
||||||
|
|
||||||
@client.on(events.CallbackQuery)
|
|
||||||
async def callback(event):
|
|
||||||
await event.edit('Thank you for clicking {}!'.format(event.data))
|
|
||||||
|
|
||||||
client.send_message(chat, 'A single button, with "clk1" as data',
|
|
||||||
buttons=Button.inline('Click me', b'clk1'))
|
|
||||||
|
|
||||||
client.send_message(chat, 'Pick one from this grid', buttons=[
|
|
||||||
[Button.inline('Left'), Button.inline('Right')],
|
|
||||||
[Button.url('Check this site!', 'https://lonamiwebs.github.io')]
|
|
||||||
])
|
|
||||||
|
|
||||||
You can also use normal buttons (not inline) to request the user's
|
|
||||||
location, phone number, or simply for them to easily send a message:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message(chat, 'Welcome', buttons=[
|
|
||||||
Button.text('Thanks!', resize=True, single_use=True),
|
|
||||||
Button.request_phone('Send phone'),
|
|
||||||
Button.request_location('Send location')
|
|
||||||
])
|
|
||||||
|
|
||||||
Forcing a reply or removing the keyboard can also be done:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
|
|
||||||
client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
|
|
||||||
|
|
||||||
Remember to check `Button <telethon.tl.custom.button.Button>` for more.
|
|
||||||
|
|
||||||
Making Inline Queries
|
|
||||||
*********************
|
|
||||||
|
|
||||||
You can send messages ``via @bot`` by first making an inline query:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
results = client.inline_query('like', 'Do you like Telethon?')
|
|
||||||
|
|
||||||
Then access the result you want and `click
|
|
||||||
<telethon.tl.custom.inlineresult.InlineResult.click>` it in the chat
|
|
||||||
where you want to send it to:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message = results[0].click('TelethonOffTopic')
|
|
||||||
|
|
||||||
Sending messages through inline bots lets you use buttons as a normal user.
|
|
||||||
|
|
||||||
It can look a bit strange at first, but you can make inline queries in no
|
|
||||||
chat in particular, and then click a *result* to send it to some chat.
|
|
||||||
|
|
||||||
Clicking Buttons
|
|
||||||
****************
|
|
||||||
|
|
||||||
Let's `click <telethon.tl.custom.message.Message.click>`
|
|
||||||
the message we sent in the example above!
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
message.click(0)
|
|
||||||
|
|
||||||
This will click the first button in the message. You could also
|
|
||||||
``click(row, column)``, using some text such as ``click(text='👍')``
|
|
||||||
or even the data directly ``click(data=b'payload')``.
|
|
||||||
|
|
||||||
Answering Inline Queries
|
|
||||||
************************
|
|
||||||
|
|
||||||
As a bot, you can answer to inline queries with `events.InlineQuery
|
|
||||||
<telethon.events.inlinequery.InlineQuery>`. You should make use of the
|
|
||||||
`builder <telethon.tl.custom.inlinebuilder.InlineBuilder>` property
|
|
||||||
to conveniently build the list of results to show to the user. Remember
|
|
||||||
to check the properties of the `InlineQuery.Event
|
|
||||||
<telethon.events.inlinequery.InlineQuery.Event>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
@bot.on(events.InlineQuery)
|
|
||||||
async def handler(event):
|
|
||||||
builder = event.builder
|
|
||||||
|
|
||||||
rev_text = event.text[::-1]
|
|
||||||
await event.answer([
|
|
||||||
builder.article('Reverse text', text=rev_text),
|
|
||||||
builder.photo('/path/to/photo.jpg')
|
|
||||||
])
|
|
||||||
|
|
||||||
Conversations: Waiting for Messages or Replies
|
|
||||||
**********************************************
|
|
||||||
|
|
||||||
This one is really useful for unit testing your bots, which you can
|
|
||||||
even write within Telethon itself! You can open a `Conversation
|
|
||||||
<telethon.tl.custom.conversation.Conversation>` in any chat as:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with client.conversation(chat) as conv:
|
|
||||||
...
|
|
||||||
|
|
||||||
Conversations let you program a finite state machine with the
|
|
||||||
higher-level constructs we are all used to, such as ``while``
|
|
||||||
and ``if`` conditionals instead setting the state and jumping
|
|
||||||
from one place to another which is less clean.
|
|
||||||
|
|
||||||
For instance, let's imagine ``you`` are the bot talking to ``usr``:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
<you> Hi!
|
|
||||||
<usr> Hello!
|
|
||||||
<you> Please tell me your name
|
|
||||||
<usr> ?
|
|
||||||
<you> Your name didn't have any letters! Try again
|
|
||||||
<usr> Lonami
|
|
||||||
<you> Thanks Lonami!
|
|
||||||
|
|
||||||
This can be programmed as follows:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
with bot.conversation(chat) as conv:
|
|
||||||
conv.send_message('Hi!')
|
|
||||||
hello = conv.get_response()
|
|
||||||
|
|
||||||
conv.send_message('Please tell me your name')
|
|
||||||
name = conv.get_response().raw_text
|
|
||||||
while not any(x.isalpha() for x in name):
|
|
||||||
conv.send_message("Your name didn't have any letters! Try again")
|
|
||||||
name = conv.get_response().raw_text
|
|
||||||
|
|
||||||
conv.send_message('Thanks {}!'.format(name))
|
|
||||||
|
|
||||||
Note how we sent a message **with the conversation**, not with the client.
|
|
||||||
This is important so the conversation remembers what messages you sent.
|
|
||||||
|
|
||||||
The method reference for getting a response, getting a reply or marking
|
|
||||||
the conversation as read can be found by clicking here: `Conversation
|
|
||||||
<telethon.tl.custom.conversation.Conversation>`.
|
|
||||||
|
|
||||||
Sending a message or getting a response returns a `Message
|
|
||||||
<telethon.tl.custom.message.Message>`. Reading its documentation
|
|
||||||
will also be really useful!
|
|
||||||
|
|
||||||
If a reply never arrives or too many messages come in, getting
|
|
||||||
responses will raise ``asyncio.TimeoutError`` or ``ValueError``
|
|
||||||
respectively. You may want to ``except`` these and tell the user
|
|
||||||
they were too slow, or simply drop the conversation.
|
|
||||||
|
|
||||||
|
|
||||||
Forwarding Messages
|
|
||||||
*******************
|
|
||||||
|
|
||||||
You can forward up to 100 messages with `forward_messages
|
|
||||||
<telethon.client.messages.MessageMethods.forward_messages>`,
|
|
||||||
or a single one if you have the message with `forward_to
|
|
||||||
<telethon.tl.custom.message.Message.forward_to>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# a single one
|
|
||||||
client.forward_messages(chat, message)
|
|
||||||
# or
|
|
||||||
client.forward_messages(chat, message_id, from_chat)
|
|
||||||
# or
|
|
||||||
message.forward_to(chat)
|
|
||||||
|
|
||||||
# multiple
|
|
||||||
client.forward_messages(chat, messages)
|
|
||||||
# or
|
|
||||||
client.forward_messages(chat, message_ids, from_chat)
|
|
||||||
|
|
||||||
You can also "forward" messages without showing "Forwarded from" by
|
|
||||||
re-sending the message:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_message(chat, message)
|
|
||||||
|
|
||||||
|
|
||||||
Editing Messages
|
|
||||||
****************
|
|
||||||
|
|
||||||
With `edit_message <telethon.client.messages.MessageMethods.edit_message>`
|
|
||||||
or `message.edit <telethon.tl.custom.message.Message.edit>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.edit_message(message, 'New text')
|
|
||||||
# or
|
|
||||||
message.edit('New text')
|
|
||||||
# or
|
|
||||||
client.edit_message(chat, message_id, 'New text')
|
|
||||||
|
|
||||||
Deleting Messages
|
|
||||||
*****************
|
|
||||||
|
|
||||||
With `delete_messages <telethon.client.messages.MessageMethods.delete_messages>`
|
|
||||||
or `message.delete <telethon.tl.custom.message.Message.delete>`. Note that the
|
|
||||||
first one supports deleting entire chats at once!:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.delete_messages(chat, messages)
|
|
||||||
# or
|
|
||||||
message.delete()
|
|
||||||
|
|
||||||
|
|
||||||
Marking Messages as Read
|
|
||||||
************************
|
|
||||||
|
|
||||||
Marking messages up to a certain point as read with `send_read_acknowledge
|
|
||||||
<telethon.client.messages.MessageMethods.send_read_acknowledge>`:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
client.send_read_acknowledge(last_message)
|
|
||||||
# or
|
|
||||||
client.send_read_acknowledge(last_message_id)
|
|
||||||
# or
|
|
||||||
client.send_read_acknowledge(messages)
|
|
||||||
|
|
||||||
|
|
||||||
Getting Entities
|
|
||||||
****************
|
|
||||||
|
|
||||||
Entities are users, chats, or channels. You can get them by their ID if
|
|
||||||
you have seen them before (e.g. you probably need to get all dialogs or
|
|
||||||
all the members from a chat first):
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from telethon import utils
|
|
||||||
|
|
||||||
me = client.get_entity('me')
|
|
||||||
print(utils.get_display_name(me))
|
|
||||||
|
|
||||||
chat = client.get_input_entity('username')
|
|
||||||
for message in client.iter_messages(chat):
|
|
||||||
...
|
|
||||||
|
|
||||||
# Note that you could have used the username directly, but it's
|
|
||||||
# good to use get_input_entity if you will reuse it a lot.
|
|
||||||
for message in client.iter_messages('username'):
|
|
||||||
...
|
|
||||||
|
|
||||||
# Note that for this to work the phone number must be in your contacts
|
|
||||||
some_id = client.get_peer_id('+34123456789')
|
|
||||||
|
|
||||||
The documentation for shown methods are `get_entity
|
|
||||||
<telethon.client.users.UserMethods.get_entity>`, `get_input_entity
|
|
||||||
<telethon.client.users.UserMethods.get_input_entity>` and `get_peer_id
|
|
||||||
<telethon.client.users.UserMethods.get_peer_id>`.
|
|
||||||
|
|
||||||
Note that the utils package also has a `get_peer_id
|
|
||||||
<telethon.utils.get_peer_id>` but it won't work with things
|
|
||||||
that need access to the network such as usernames or phones,
|
|
||||||
which need to be in your contact list.
|
|
||||||
|
|
||||||
Getting the Admin Log
|
|
||||||
*********************
|
|
||||||
|
|
||||||
If you're an administrator in a channel or megagroup, then you have access
|
|
||||||
to the admin log. This is a list of events within the last 48 hours of
|
|
||||||
different actions, such as joining or leaving members, edited or deleted
|
|
||||||
messages, new promotions, bans or restrictions.
|
|
||||||
|
|
||||||
You can iterate over all the available actions like so:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
for event in client.iter_admin_log(channel):
|
|
||||||
if event.changed_title:
|
|
||||||
print('The title changed from', event.old, 'to', event.new)
|
|
||||||
|
|
||||||
You can also filter to only show some text or actions.
|
|
||||||
Let's find people who swear to ban them:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
# Get a list of deleted message events which said "heck"
|
|
||||||
events = client.get_admin_log(channel, search='heck', delete=True)
|
|
||||||
|
|
||||||
# Print the old message before it was deleted
|
|
||||||
print(events[0].old)
|
|
||||||
|
|
||||||
You can find here the documentation for `client.iter_admin_log
|
|
||||||
<telethon.client.chats.ChatMethods.iter_admin_log>`, and be sure
|
|
||||||
to also check the properties of the returned `AdminLogEvent
|
|
||||||
<telethon.tl.custom.adminlogevent.AdminLogEvent>` to know what
|
|
||||||
you can access.
|
|
|
@ -1,27 +0,0 @@
|
||||||
========================================
|
|
||||||
Deleted, Limited or Deactivated Accounts
|
|
||||||
========================================
|
|
||||||
|
|
||||||
If you're from Iran or Russia, we have bad news for you. Telegram is much more
|
|
||||||
likely to ban these numbers, as they are often used to spam other accounts,
|
|
||||||
likely through the use of libraries like this one. The best advice we can
|
|
||||||
give you is to not abuse the API, like calling many requests really quickly,
|
|
||||||
and to sign up with these phones through an official application.
|
|
||||||
|
|
||||||
We have also had reports from Kazakhstan and China, where connecting
|
|
||||||
would fail. To solve these connection problems, you should use a proxy.
|
|
||||||
|
|
||||||
Telegram may also ban virtual (VoIP) phone numbers,
|
|
||||||
as again, they're likely to be used for spam.
|
|
||||||
|
|
||||||
If you want to check if your account has been limited,
|
|
||||||
simply send a private message to `@SpamBot`__ through Telegram itself.
|
|
||||||
You should notice this by getting errors like ``PeerFloodError``,
|
|
||||||
which means you're limited, for instance,
|
|
||||||
when sending a message to some accounts but not others.
|
|
||||||
|
|
||||||
For more discussion, please see `issue 297`__.
|
|
||||||
|
|
||||||
|
|
||||||
__ https://t.me/SpamBot
|
|
||||||
__ https://github.com/LonamiWebs/Telethon/issues/297
|
|
|
@ -1,40 +0,0 @@
|
||||||
================
|
|
||||||
Enabling Logging
|
|
||||||
================
|
|
||||||
|
|
||||||
Telethon makes use of the `logging`__ module, and you can enable it as follows:
|
|
||||||
|
|
||||||
.. code:: python
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logging.basicConfig(level=logging.DEBUG)
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
import logging
|
|
||||||
logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
logger.debug('Debug messages')
|
|
||||||
logger.info('Useful information')
|
|
||||||
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/howto/logging.html#configuring-logging-for-a-library
|
|
||||||
__ https://docs.python.org/3/howto/logging.html
|
|
|
@ -1,29 +1,31 @@
|
||||||
.. Telethon documentation master file, created by
|
========================
|
||||||
sphinx-quickstart on Fri Nov 17 15:36:11 2017.
|
Telethon's Documentation
|
||||||
You can adapt this file completely to your liking, but it should at least
|
========================
|
||||||
contain the root `toctree` directive.
|
|
||||||
|
|
||||||
====================================
|
.. code-block:: python
|
||||||
Welcome to Telethon's documentation!
|
|
||||||
====================================
|
from telethon.sync import TelegramClient, events
|
||||||
|
|
||||||
|
with TelegramClient('name', api_id, api_hash) as client:
|
||||||
|
client.send_message('me', 'Hello, myself!')
|
||||||
|
print(client.download_profile_photo('me'))
|
||||||
|
|
||||||
|
@client.on(events.NewMessage(pattern='(?i).*Hello'))
|
||||||
|
async def handler(event):
|
||||||
|
await event.reply('Hey!')
|
||||||
|
|
||||||
|
client.run_until_disconnected()
|
||||||
|
|
||||||
|
|
||||||
Pure Python 3 Telegram client library.
|
* Are you new here? Jump straight into :ref:`installation`!
|
||||||
Official Site `here <https://lonamiwebs.github.io/Telethon>`_.
|
* Looking for the method reference? See :ref:`client-ref`.
|
||||||
Please follow the links on the index below to navigate from here,
|
* Did you upgrade the library? Please read :ref:`changelog`.
|
||||||
or use the menu on the left. Remember to read the :ref:`changelog`
|
* Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
|
||||||
when you upgrade!
|
* Need the full API reference? https://lonamiwebs.github.io/Telethon/.
|
||||||
|
|
||||||
.. important::
|
|
||||||
|
|
||||||
* Are you new here? Jump straight into :ref:`getting-started`!
|
|
||||||
* Looking for available friendly methods? See :ref:`ref-summary`.
|
|
||||||
* Used Telethon before v1.0? See :ref:`compatibility-and-convenience`.
|
|
||||||
* Need the full API reference? https://lonamiwebs.github.io/Telethon/.
|
|
||||||
|
|
||||||
|
|
||||||
What is this?
|
What is this?
|
||||||
*************
|
-------------
|
||||||
|
|
||||||
Telegram is a popular messaging application. This library is meant
|
Telegram is a popular messaging application. This library is meant
|
||||||
to make it easy for you to write Python programs that can interact
|
to make it easy for you to write Python programs that can interact
|
||||||
|
@ -31,93 +33,84 @@ with Telegram. Think of it as a wrapper that has already done the
|
||||||
heavy job for you, so you can focus on developing an application.
|
heavy job for you, so you can focus on developing an application.
|
||||||
|
|
||||||
|
|
||||||
.. _installation-and-usage:
|
How should I use the documentation?
|
||||||
|
-----------------------------------
|
||||||
|
|
||||||
|
If you are getting started with the library, you should follow the
|
||||||
|
documentation in order by pressing the "Next" button at the bottom-right
|
||||||
|
of every page.
|
||||||
|
|
||||||
|
You can also use the menu on the left to quickly skip over sections.
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Installation and Simple Usage
|
:caption: First Steps
|
||||||
|
|
||||||
extra/basic/getting-started
|
basic/installation
|
||||||
extra/basic/installation
|
basic/signing-in
|
||||||
extra/basic/creating-a-client
|
basic/quick-start
|
||||||
extra/basic/telegram-client
|
basic/updates
|
||||||
extra/reference
|
basic/next-steps
|
||||||
extra/basic/entities
|
|
||||||
extra/basic/working-with-updates
|
|
||||||
extra/basic/compatibility-and-convenience
|
|
||||||
|
|
||||||
|
|
||||||
.. _Advanced-usage:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Advanced Usage
|
:caption: Quick References
|
||||||
|
|
||||||
extra/advanced-usage/accessing-the-full-api
|
quick-references/faq
|
||||||
extra/advanced-usage/sessions
|
quick-references/client-reference
|
||||||
extra/advanced-usage/update-modes
|
quick-references/events-reference
|
||||||
extra/advanced-usage/mastering-telethon
|
quick-references/objects-reference
|
||||||
extra/advanced-usage/mastering-asyncio
|
|
||||||
|
|
||||||
|
|
||||||
.. _Examples:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Examples
|
:caption: Concepts
|
||||||
|
|
||||||
extra/examples/telegram-client
|
concepts/strings
|
||||||
extra/examples/working-with-messages
|
concepts/entities
|
||||||
extra/examples/chats-and-channels
|
concepts/updates
|
||||||
extra/examples/users
|
concepts/sessions
|
||||||
extra/examples/projects-using-telethon
|
concepts/full-api
|
||||||
|
concepts/errors
|
||||||
|
concepts/asyncio
|
||||||
.. _Troubleshooting:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Troubleshooting
|
:caption: Full API Examples
|
||||||
|
|
||||||
extra/troubleshooting/enable-logging
|
examples/word-of-warning
|
||||||
extra/troubleshooting/deleted-limited-or-deactivated-accounts
|
examples/chats-and-channels
|
||||||
extra/troubleshooting/rpc-errors
|
examples/users
|
||||||
|
examples/working-with-messages
|
||||||
|
examples/projects-using-telethon
|
||||||
.. _Developing:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: Developing
|
:caption: Developing
|
||||||
|
|
||||||
extra/developing/philosophy.rst
|
developing/philosophy.rst
|
||||||
extra/developing/test-servers.rst
|
developing/test-servers.rst
|
||||||
extra/developing/project-structure.rst
|
developing/project-structure.rst
|
||||||
extra/developing/coding-style.rst
|
developing/coding-style.rst
|
||||||
extra/developing/understanding-the-type-language.rst
|
developing/understanding-the-type-language.rst
|
||||||
extra/developing/tips-for-porting-the-project.rst
|
developing/tips-for-porting-the-project.rst
|
||||||
extra/developing/telegram-api-in-other-languages.rst
|
developing/telegram-api-in-other-languages.rst
|
||||||
|
|
||||||
|
|
||||||
.. _More:
|
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:maxdepth: 2
|
:hidden:
|
||||||
:caption: More
|
:caption: Miscellaneous
|
||||||
|
|
||||||
extra/changelog
|
|
||||||
extra/wall-of-shame.rst
|
|
||||||
|
|
||||||
|
misc/changelog
|
||||||
|
misc/wall-of-shame.rst
|
||||||
|
misc/compatibility-and-convenience
|
||||||
|
|
||||||
.. toctree::
|
.. toctree::
|
||||||
:caption: Telethon modules
|
:hidden:
|
||||||
|
:caption: Telethon Modules
|
||||||
|
|
||||||
modules
|
modules/client
|
||||||
|
modules/events
|
||||||
|
modules/custom
|
||||||
Indices and tables
|
modules/utils
|
||||||
==================
|
modules/errors
|
||||||
|
modules/sessions
|
||||||
* :ref:`genindex`
|
modules/network
|
||||||
* :ref:`modindex`
|
|
||||||
* :ref:`search`
|
|
||||||
|
|
|
@ -867,7 +867,7 @@ Additions
|
||||||
<telethon.events.callbackquery.CallbackQuery>`.
|
<telethon.events.callbackquery.CallbackQuery>`.
|
||||||
- New ``silent`` parameter when sending messages, usable in broadcast channels.
|
- New ``silent`` parameter when sending messages, usable in broadcast channels.
|
||||||
- Documentation now has an entire section dedicate to how to use
|
- Documentation now has an entire section dedicate to how to use
|
||||||
the client's friendly methods at :ref:`telegram-client-example`.
|
the client's friendly methods at *(removed broken link)*.
|
||||||
|
|
||||||
Bug fixes
|
Bug fixes
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
@ -924,7 +924,7 @@ Additions
|
||||||
~~~~~~~~~
|
~~~~~~~~~
|
||||||
|
|
||||||
- ``add_mark=`` is now back on ``utils.get_input_peer`` and also on
|
- ``add_mark=`` is now back on ``utils.get_input_peer`` and also on
|
||||||
`client.get_input_entity <telethon.client.users.UserMethods.get_input_entity>`.
|
`client.get_input_entity() <telethon.client.users.UserMethods.get_input_entity>`.
|
||||||
- New `client.get_peer_id <telethon.client.users.UserMethods.get_peer_id>`
|
- New `client.get_peer_id <telethon.client.users.UserMethods.get_peer_id>`
|
||||||
convenience for ``utils.get_peer_id(await client.get_input_entity(peer))``.
|
convenience for ``utils.get_peer_id(await client.get_input_entity(peer))``.
|
||||||
|
|
||||||
|
@ -1776,7 +1776,7 @@ Of course there was more work to be done regarding updates, and it's here!
|
||||||
The library comes with a new ``events`` module (which you will often import
|
The library comes with a new ``events`` module (which you will often import
|
||||||
as ``from telethon import TelegramClient, events``). This are pretty much
|
as ``from telethon import TelegramClient, events``). This are pretty much
|
||||||
all the additions that come with this version change, but they are a nice
|
all the additions that come with this version change, but they are a nice
|
||||||
addition. Refer to :ref:`working-with-updates` to get started with events.
|
addition. Refer to *(removed broken link)* to get started with events.
|
||||||
|
|
||||||
|
|
||||||
Trust the Server with Updates (v0.17)
|
Trust the Server with Updates (v0.17)
|
|
@ -12,7 +12,7 @@ is there to tell you when these important changes happen.
|
||||||
|
|
||||||
|
|
||||||
Compatibility
|
Compatibility
|
||||||
*************
|
=============
|
||||||
|
|
||||||
Some decisions when developing will inevitable be proven wrong in the future.
|
Some decisions when developing will inevitable be proven wrong in the future.
|
||||||
One of these decisions was using threads. Now that Python 3.4 is reaching EOL
|
One of these decisions was using threads. Now that Python 3.4 is reaching EOL
|
||||||
|
@ -76,7 +76,7 @@ the chat or sender. If you don't use updates, you're done!
|
||||||
|
|
||||||
|
|
||||||
Convenience
|
Convenience
|
||||||
***********
|
===========
|
||||||
|
|
||||||
.. note::
|
.. note::
|
||||||
|
|
||||||
|
@ -134,7 +134,7 @@ This keeps the best of both worlds as a sane default.
|
||||||
them too. Otherwise, there is no need to do so with this mode.
|
them too. Otherwise, there is no need to do so with this mode.
|
||||||
|
|
||||||
Speed
|
Speed
|
||||||
*****
|
=====
|
||||||
|
|
||||||
When you're ready to micro-optimize your application, or if you simply
|
When you're ready to micro-optimize your application, or if you simply
|
||||||
don't need to call any non-basic methods from a synchronous context,
|
don't need to call any non-basic methods from a synchronous context,
|
||||||
|
@ -176,7 +176,7 @@ So that you don't have to write it yourself every time. That's the
|
||||||
overhead you pay if you import it, and what you save if you don't.
|
overhead you pay if you import it, and what you save if you don't.
|
||||||
|
|
||||||
Learning
|
Learning
|
||||||
********
|
========
|
||||||
|
|
||||||
You know the library uses ``asyncio`` everywhere, and you want to learn
|
You know the library uses ``asyncio`` everywhere, and you want to learn
|
||||||
how to do things right. Even though ``asyncio`` is its own topic, the
|
how to do things right. Even though ``asyncio`` is its own topic, the
|
|
@ -1,7 +0,0 @@
|
||||||
telethon
|
|
||||||
========
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
:maxdepth: 3
|
|
||||||
|
|
||||||
telethon
|
|
|
@ -1,12 +1,14 @@
|
||||||
.. _telethon-client:
|
.. _telethon-client:
|
||||||
|
|
||||||
|
==============
|
||||||
|
TelegramClient
|
||||||
|
==============
|
||||||
|
|
||||||
telethon\.client package
|
.. currentmodule:: telethon.client
|
||||||
========================
|
|
||||||
|
|
||||||
The `telethon.TelegramClient` aggregates several mixin classes to provide
|
The `TelegramClient <telegramclient.TelegramClient>` aggregates several mixin
|
||||||
all the common functionality in a nice, Pythonic interface. Each mixin has
|
classes to provide all the common functionality in a nice, Pythonic interface.
|
||||||
its own methods, which you all can use.
|
Each mixin has its own methods, which you all can use.
|
||||||
|
|
||||||
**In short, to create a client you must run:**
|
**In short, to create a client you must run:**
|
||||||
|
|
||||||
|
@ -24,8 +26,15 @@ its own methods, which you all can use.
|
||||||
|
|
||||||
|
|
||||||
You **don't** need to import these `AuthMethods`, `MessageMethods`, etc.
|
You **don't** need to import these `AuthMethods`, `MessageMethods`, etc.
|
||||||
Together they are the `telethon.TelegramClient` and you can access all of
|
Together they are the `TelegramClient <telegramclient.TelegramClient>` and
|
||||||
their methods.
|
you can access all of their methods.
|
||||||
|
|
||||||
|
See :ref:`client-ref` for a short summary.
|
||||||
|
|
||||||
|
.. automodule:: telethon.client.telegramclient
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
.. automodule:: telethon.client.telegrambaseclient
|
.. automodule:: telethon.client.telegrambaseclient
|
||||||
:members:
|
:members:
|
|
@ -1,115 +1,145 @@
|
||||||
telethon\.tl\.custom package
|
==============
|
||||||
============================
|
Custom package
|
||||||
|
==============
|
||||||
|
|
||||||
|
The `telethon.tl.custom` package contains custom classes that the library
|
||||||
|
uses in order to make working with Telegram easier. Only those that you
|
||||||
|
are supposed to use will be documented here. You can use undocumented ones
|
||||||
|
at your own risk.
|
||||||
|
|
||||||
telethon\.tl\.custom\.draft module
|
More often than not, you don't need to import these (unless you want
|
||||||
----------------------------------
|
type hinting), nor do you need to manually create instances of these
|
||||||
|
classes. They are returned by client methods.
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.draft
|
.. contents::
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
telethon\.tl\.custom\.dialog module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.dialog
|
AdminLogEvent
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.adminlogevent
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
telethon\.tl\.custom\.file module
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.file
|
Button
|
||||||
:members:
|
======
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.message module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.message
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.messagebutton module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.messagebutton
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.forward module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.forward
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.button module
|
|
||||||
-----------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.button
|
.. automodule:: telethon.tl.custom.button
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
telethon\.tl\.custom\.inlinebuilder module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.inlinebuilder
|
ChatGetter
|
||||||
:members:
|
==========
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.inlineresult module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.inlineresult
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.inlineresults module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.inlineresults
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.chatgetter module
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.chatgetter
|
.. automodule:: telethon.tl.custom.chatgetter
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
telethon\.tl\.custom\.sendergetter module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.sendergetter
|
Conversation
|
||||||
:members:
|
============
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.tl\.custom\.conversation module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.conversation
|
.. automodule:: telethon.tl.custom.conversation
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
telethon\.tl\.custom\.adminlogevent module
|
|
||||||
------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.custom.adminlogevent
|
Dialog
|
||||||
|
======
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.dialog
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
Draft
|
||||||
|
=====
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.draft
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
File
|
||||||
|
====
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.file
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
Forward
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.forward
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
InlineBuilder
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.inlinebuilder
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
InlineResult
|
||||||
|
============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.inlineresult
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
InlineResults
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.inlineresults
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
Message
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.message
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
MessageButton
|
||||||
|
=============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.messagebutton
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
SenderGetter
|
||||||
|
============
|
||||||
|
|
||||||
|
.. automodule:: telethon.tl.custom.sendergetter
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
19
readthedocs/modules/errors.rst
Normal file
19
readthedocs/modules/errors.rst
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.. _telethon-errors:
|
||||||
|
|
||||||
|
==========
|
||||||
|
API Errors
|
||||||
|
==========
|
||||||
|
|
||||||
|
These are the base errors that Telegram's API may raise.
|
||||||
|
|
||||||
|
See :ref:`rpc-errors` for a more friendly explanation.
|
||||||
|
|
||||||
|
.. automodule:: telethon.errors.common
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.errors.rpcbaseerrors
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
|
@ -1,9 +1,12 @@
|
||||||
.. _telethon-events-package:
|
.. _telethon-events:
|
||||||
|
|
||||||
telethon\.events package
|
=============
|
||||||
========================
|
Update Events
|
||||||
|
=============
|
||||||
|
|
||||||
Every event (builder) subclasses `telethon.events.common.EventBuilder`,
|
.. currentmodule:: telethon.events
|
||||||
|
|
||||||
|
Every event (builder) subclasses `common.EventBuilder`,
|
||||||
so all the methods in it can be used from any event builder/event instance.
|
so all the methods in it can be used from any event builder/event instance.
|
||||||
|
|
||||||
.. automodule:: telethon.events.common
|
.. automodule:: telethon.events.common
|
||||||
|
@ -11,62 +14,51 @@ so all the methods in it can be used from any event builder/event instance.
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.newmessage
|
.. automodule:: telethon.events.newmessage
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.chataction
|
.. automodule:: telethon.events.chataction
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.userupdate
|
.. automodule:: telethon.events.userupdate
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.messageedited
|
.. automodule:: telethon.events.messageedited
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.messagedeleted
|
.. automodule:: telethon.events.messagedeleted
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.messageread
|
.. automodule:: telethon.events.messageread
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.callbackquery
|
.. automodule:: telethon.events.callbackquery
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.inlinequery
|
.. automodule:: telethon.events.inlinequery
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events.raw
|
.. automodule:: telethon.events.raw
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
||||||
:show-inheritance:
|
:show-inheritance:
|
||||||
|
|
||||||
|
|
||||||
.. automodule:: telethon.events
|
.. automodule:: telethon.events
|
||||||
:members:
|
:members:
|
||||||
:undoc-members:
|
:undoc-members:
|
8
readthedocs/modules/helpers.rst
Normal file
8
readthedocs/modules/helpers.rst
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
=======
|
||||||
|
Helpers
|
||||||
|
=======
|
||||||
|
|
||||||
|
.. automodule:: telethon.helpers
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
33
readthedocs/modules/network.rst
Normal file
33
readthedocs/modules/network.rst
Normal file
|
@ -0,0 +1,33 @@
|
||||||
|
.. _telethon-network:
|
||||||
|
|
||||||
|
================
|
||||||
|
Connection Modes
|
||||||
|
================
|
||||||
|
|
||||||
|
The only part about network that you should worry about are
|
||||||
|
the different connection modes, which are the following:
|
||||||
|
|
||||||
|
.. automodule:: telethon.network.connection.tcpfull
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.network.connection.tcpabridged
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.network.connection.tcpintermediate
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.network.connection.tcpobfuscated
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.network.connection.http
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
27
readthedocs/modules/sessions.rst
Normal file
27
readthedocs/modules/sessions.rst
Normal file
|
@ -0,0 +1,27 @@
|
||||||
|
.. _telethon-sessions:
|
||||||
|
|
||||||
|
========
|
||||||
|
Sessions
|
||||||
|
========
|
||||||
|
|
||||||
|
These are the different built-in session storage that you may subclass.
|
||||||
|
|
||||||
|
.. automodule:: telethon.sessions.abstract
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.sessions.memory
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.sessions.sqlite
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
||||||
|
|
||||||
|
.. automodule:: telethon.sessions.string
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
12
readthedocs/modules/utils.rst
Normal file
12
readthedocs/modules/utils.rst
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
.. _telethon-utils:
|
||||||
|
|
||||||
|
=========
|
||||||
|
Utilities
|
||||||
|
=========
|
||||||
|
|
||||||
|
These are the utilities that the library has to offer.
|
||||||
|
|
||||||
|
.. automodule:: telethon.utils
|
||||||
|
:members:
|
||||||
|
:undoc-members:
|
||||||
|
:show-inheritance:
|
188
readthedocs/quick-references/client-reference.rst
Normal file
188
readthedocs/quick-references/client-reference.rst
Normal file
|
@ -0,0 +1,188 @@
|
||||||
|
.. _client-ref:
|
||||||
|
|
||||||
|
================
|
||||||
|
Client Reference
|
||||||
|
================
|
||||||
|
|
||||||
|
This page contains a summary of all the important methods and properties that
|
||||||
|
you may need when using Telethon. They are sorted by relevance and are not in
|
||||||
|
alphabetical order.
|
||||||
|
|
||||||
|
You should use this page to learn about which methods are available, and
|
||||||
|
if you need an usage example or further description of the arguments, be
|
||||||
|
sure to follow the links.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
TelegramClient
|
||||||
|
==============
|
||||||
|
|
||||||
|
This is a summary of the methods and
|
||||||
|
properties you will find at :ref:`telethon-client`.
|
||||||
|
|
||||||
|
Auth
|
||||||
|
----
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.auth.AuthMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
start
|
||||||
|
send_code_request
|
||||||
|
sign_in
|
||||||
|
sign_up
|
||||||
|
log_out
|
||||||
|
edit_2fa
|
||||||
|
|
||||||
|
Base
|
||||||
|
----
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
connect
|
||||||
|
disconnect
|
||||||
|
is_connected
|
||||||
|
disconnected
|
||||||
|
loop
|
||||||
|
|
||||||
|
Messages
|
||||||
|
--------
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.messages.MessageMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
send_message
|
||||||
|
edit_message
|
||||||
|
delete_messages
|
||||||
|
forward_messages
|
||||||
|
iter_messages
|
||||||
|
get_messages
|
||||||
|
send_read_acknowledge
|
||||||
|
|
||||||
|
Uploads
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.uploads.UploadMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
send_file
|
||||||
|
upload_file
|
||||||
|
|
||||||
|
Downloads
|
||||||
|
---------
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.downloads.DownloadMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
download_media
|
||||||
|
download_profile_photo
|
||||||
|
download_file
|
||||||
|
|
||||||
|
Dialogs
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.dialogs.DialogMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
iter_dialogs
|
||||||
|
get_dialogs
|
||||||
|
iter_drafts
|
||||||
|
get_drafts
|
||||||
|
conversation
|
||||||
|
|
||||||
|
Users
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.users.UserMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
get_me
|
||||||
|
is_bot
|
||||||
|
is_user_authorized
|
||||||
|
get_entity
|
||||||
|
get_input_entity
|
||||||
|
get_peer_id
|
||||||
|
|
||||||
|
Chats
|
||||||
|
-----
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.chats.ChatMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
iter_participants
|
||||||
|
get_participants
|
||||||
|
iter_admin_log
|
||||||
|
get_admin_log
|
||||||
|
action
|
||||||
|
|
||||||
|
Parse Mode
|
||||||
|
----------
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
parse_mode
|
||||||
|
|
||||||
|
Updates
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. py:currentmodule:: telethon.client.updates.UpdateMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
on
|
||||||
|
run_until_disconnected
|
||||||
|
add_event_handler
|
||||||
|
remove_event_handler
|
||||||
|
list_event_handlers
|
||||||
|
catch_up
|
||||||
|
|
||||||
|
Bots
|
||||||
|
----
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.bots.BotMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
inline_query
|
||||||
|
|
||||||
|
Buttons
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.buttons.ButtonMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
build_reply_markup
|
||||||
|
|
||||||
|
Account
|
||||||
|
-------
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.client.account.AccountMethods
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
takeout
|
||||||
|
end_takeout
|
203
readthedocs/quick-references/events-reference.rst
Normal file
203
readthedocs/quick-references/events-reference.rst
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
================
|
||||||
|
Events Reference
|
||||||
|
================
|
||||||
|
|
||||||
|
Here you will find a quick summary of all the methods
|
||||||
|
and properties that you can access when working with events.
|
||||||
|
|
||||||
|
You can access the client that creates this event by doing
|
||||||
|
``event.client``, and you should view the description of the
|
||||||
|
events to find out what arguments it allows on creation and
|
||||||
|
its **attributes** (the properties will be shown here).
|
||||||
|
|
||||||
|
It is important to remember that **all events subclass**
|
||||||
|
`ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`!
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
ChatGetter
|
||||||
|
==========
|
||||||
|
|
||||||
|
All events subclass `ChatGetter <telethon.tl.custom.chatgetter.ChatGetter>`,
|
||||||
|
which means all events have (and you can access to):
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.tl.custom.chatgetter.ChatGetter
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
chat
|
||||||
|
input_chat
|
||||||
|
chat_id
|
||||||
|
is_private
|
||||||
|
is_group
|
||||||
|
is_channel
|
||||||
|
|
||||||
|
get_chat
|
||||||
|
get_input_chat
|
||||||
|
|
||||||
|
|
||||||
|
CallbackQuery
|
||||||
|
=============
|
||||||
|
|
||||||
|
Full documentation for the `CallbackQuery
|
||||||
|
<telethon.events.callbackquery.CallbackQuery>`.
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.events.callbackquery.CallbackQuery.Event
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
id
|
||||||
|
message_id
|
||||||
|
data
|
||||||
|
chat_instance
|
||||||
|
via_inline
|
||||||
|
|
||||||
|
respond
|
||||||
|
reply
|
||||||
|
edit
|
||||||
|
delete
|
||||||
|
answer
|
||||||
|
get_message
|
||||||
|
|
||||||
|
|
||||||
|
ChatAction
|
||||||
|
==========
|
||||||
|
|
||||||
|
Full documentation for the `ChatAction
|
||||||
|
<telethon.events.chataction.ChatAction>`.
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.events.chataction.ChatAction.Event
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
added_by
|
||||||
|
kicked_by
|
||||||
|
user
|
||||||
|
input_user
|
||||||
|
user_id
|
||||||
|
users
|
||||||
|
input_users
|
||||||
|
user_ids
|
||||||
|
|
||||||
|
respond
|
||||||
|
reply
|
||||||
|
delete
|
||||||
|
get_pinned_message
|
||||||
|
get_added_by
|
||||||
|
get_kicked_by
|
||||||
|
get_user
|
||||||
|
get_input_user
|
||||||
|
get_users
|
||||||
|
get_input_users
|
||||||
|
|
||||||
|
|
||||||
|
InlineQuery
|
||||||
|
===========
|
||||||
|
|
||||||
|
Full documentation for the `InlineQuery
|
||||||
|
<telethon.events.inlinequery.InlineQuery>`.
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.events.inlinequery.InlineQuery.Event
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
id
|
||||||
|
text
|
||||||
|
offset
|
||||||
|
geo
|
||||||
|
builder
|
||||||
|
|
||||||
|
answer
|
||||||
|
|
||||||
|
|
||||||
|
MessageDeleted
|
||||||
|
==============
|
||||||
|
|
||||||
|
Full documentation for the `MessageDeleted
|
||||||
|
<telethon.events.messagedeleted.MessageDeleted>`.
|
||||||
|
|
||||||
|
It only has the ``deleted_id`` and ``deleted_ids`` attributes
|
||||||
|
(in addition to the chat if the deletion happened in a channel).
|
||||||
|
|
||||||
|
|
||||||
|
MessageEdited
|
||||||
|
=============
|
||||||
|
|
||||||
|
Full documentation for the `MessageEdited
|
||||||
|
<telethon.events.messageedited.MessageEdited>`.
|
||||||
|
|
||||||
|
This event is the same as `NewMessage
|
||||||
|
<telethon.events.newmessage.NewMessage>`,
|
||||||
|
but occurs only when an edit happens.
|
||||||
|
|
||||||
|
|
||||||
|
MessageRead
|
||||||
|
===========
|
||||||
|
|
||||||
|
Full documentation for the `MessageRead
|
||||||
|
<telethon.events.messageread.MessageRead>`.
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.events.messageread.MessageRead.Event
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
inbox
|
||||||
|
message_ids
|
||||||
|
|
||||||
|
get_messages
|
||||||
|
is_read
|
||||||
|
|
||||||
|
|
||||||
|
NewMessage
|
||||||
|
==========
|
||||||
|
|
||||||
|
Full documentation for the `NewMessage
|
||||||
|
<telethon.events.newmessage.NewMessage>`.
|
||||||
|
|
||||||
|
Note that the new message event **should be treated as** a
|
||||||
|
normal `Message <telethon.tl.custom.message.Message>`, with
|
||||||
|
the following exceptions:
|
||||||
|
|
||||||
|
* ``pattern_match`` is the match object returned by ``pattern=``.
|
||||||
|
* ``message`` is **not** the message string. It's the `Message
|
||||||
|
<telethon.tl.custom.message.Message>` object.
|
||||||
|
|
||||||
|
Remember, this event is just a proxy over the message, so while
|
||||||
|
you won't see its attributes and properties, you can still access
|
||||||
|
them.
|
||||||
|
|
||||||
|
|
||||||
|
Raw
|
||||||
|
===
|
||||||
|
|
||||||
|
Raw events are not actual events. Instead, they are the raw
|
||||||
|
:tl:`Update` object that Telegram sends. You normally shouldn't
|
||||||
|
need these.
|
||||||
|
|
||||||
|
|
||||||
|
UserUpdate
|
||||||
|
==========
|
||||||
|
|
||||||
|
Full documentation for the `UserUpdate
|
||||||
|
<telethon.events.userupdate.UserUpdate>`.
|
||||||
|
|
||||||
|
A lot of fields are attributes and not properties, so they
|
||||||
|
are not shown here.
|
||||||
|
|
||||||
|
.. currentmodule:: telethon.events.userupdate.UserUpdate.Event
|
||||||
|
|
||||||
|
.. autosummary::
|
||||||
|
:nosignatures:
|
||||||
|
|
||||||
|
user
|
||||||
|
input_user
|
||||||
|
user_id
|
||||||
|
|
||||||
|
get_user
|
||||||
|
get_input_user
|
190
readthedocs/quick-references/faq.rst
Normal file
190
readthedocs/quick-references/faq.rst
Normal file
|
@ -0,0 +1,190 @@
|
||||||
|
===
|
||||||
|
FAQ
|
||||||
|
===
|
||||||
|
|
||||||
|
Let's start the quick references section with some useful tips to keep in
|
||||||
|
mind, with the hope that you will understand why certain things work the
|
||||||
|
way that they do.
|
||||||
|
|
||||||
|
.. contents::
|
||||||
|
|
||||||
|
|
||||||
|
Code without errors doesn't work
|
||||||
|
================================
|
||||||
|
|
||||||
|
Then it probably has errors, but you haven't enabled logging yet.
|
||||||
|
To enable logging, at the following code to the top of your main file:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import logging
|
||||||
|
logging.basicConfig(format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
|
||||||
|
level=logging.WARNING)
|
||||||
|
|
||||||
|
You can change the logging level to be something different, from less to more information:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
level=logging.CRITICAL # won't show errors (same as disabled)
|
||||||
|
level=logging.ERROR # will only show errors that you didn't handle
|
||||||
|
level=logging.WARNING # will also show messages with medium severity, such as internal Telegram issues
|
||||||
|
level=logging.INFO # will also show informational messages, such as connection or disconnections
|
||||||
|
level=logging.DEBUG # will show a lot of output to help debugging issues in the library
|
||||||
|
|
||||||
|
See the official Python documentation for more information on logging_.
|
||||||
|
|
||||||
|
|
||||||
|
How can I except FloodWaitError?
|
||||||
|
================================
|
||||||
|
|
||||||
|
You can use all errors from the API by importing:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import errors
|
||||||
|
|
||||||
|
And except them as such:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import time
|
||||||
|
try:
|
||||||
|
client.send_message(chat, 'Hi')
|
||||||
|
except FloodWaitError as e:
|
||||||
|
print('Flood for', e.seconds)
|
||||||
|
time.sleep(e.seconds)
|
||||||
|
|
||||||
|
|
||||||
|
My account was deleted/limited when using the library
|
||||||
|
=====================================================
|
||||||
|
|
||||||
|
The library will only do things that you tell it to do. If you use
|
||||||
|
the library with bad intentions, Telegram will hopefully ban you.
|
||||||
|
|
||||||
|
However, you may also be part of a limited country, such as Iran or Russia.
|
||||||
|
In that case, we have bad news for you. Telegram is much more likely to ban
|
||||||
|
these numbers, as they are often used to spam other accounts, likely through
|
||||||
|
the use of libraries like this one. The best advice we can give you is to not
|
||||||
|
abuse the API, like calling many requests really quickly, and to sign up with
|
||||||
|
these phones through an official application.
|
||||||
|
|
||||||
|
We have also had reports from Kazakhstan and China, where connecting
|
||||||
|
would fail. To solve these connection problems, you should use a proxy.
|
||||||
|
|
||||||
|
Telegram may also ban virtual (VoIP) phone numbers,
|
||||||
|
as again, they're likely to be used for spam.
|
||||||
|
|
||||||
|
If you want to check if your account has been limited,
|
||||||
|
simply send a private message to `@SpamBot`_ through Telegram itself.
|
||||||
|
You should notice this by getting errors like ``PeerFloodError``,
|
||||||
|
which means you're limited, for instance,
|
||||||
|
when sending a message to some accounts but not others.
|
||||||
|
|
||||||
|
For more discussion, please see `issue 297`_.
|
||||||
|
|
||||||
|
|
||||||
|
How can I use a proxy?
|
||||||
|
======================
|
||||||
|
|
||||||
|
This was one of the first things described in :ref:`signing-in`.
|
||||||
|
|
||||||
|
|
||||||
|
How do I access a field?
|
||||||
|
========================
|
||||||
|
|
||||||
|
This is basic Python knowledge. You should use the dot operator:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
me = client.get_me()
|
||||||
|
print(me.username)
|
||||||
|
# ^ we used the dot operator to access the username attribute
|
||||||
|
|
||||||
|
result = client(functions.photos.GetUserPhotosRequest(
|
||||||
|
user_id='me',
|
||||||
|
offset=0,
|
||||||
|
max_id=0,
|
||||||
|
limit=100
|
||||||
|
))
|
||||||
|
|
||||||
|
# Working with list is also pretty basic
|
||||||
|
print(result.photos[0].sizes[-1].type)
|
||||||
|
# ^ ^ ^ ^ ^
|
||||||
|
# | | | | \ type
|
||||||
|
# | | | \ last size
|
||||||
|
# | | \ list of sizes
|
||||||
|
# access | \ first photo from the list
|
||||||
|
# the... \ list of photos
|
||||||
|
#
|
||||||
|
# To print all, you could do (or mix-and-match):
|
||||||
|
for photo in result.photos:
|
||||||
|
for size in photo.sizes:
|
||||||
|
print(size.type)
|
||||||
|
|
||||||
|
|
||||||
|
AttributeError: 'coroutine' object has no attribute 'id'
|
||||||
|
========================================================
|
||||||
|
|
||||||
|
You either forgot to:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
import telethon.sync
|
||||||
|
# ^^^^^ import sync
|
||||||
|
|
||||||
|
Or:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
me = await client.get_me()
|
||||||
|
# ^^^^^ note the await
|
||||||
|
print(me.username)
|
||||||
|
|
||||||
|
|
||||||
|
sqlite3.OperationalError: database is locked
|
||||||
|
============================================
|
||||||
|
|
||||||
|
An older process is still running and is using the same ``'session'`` file.
|
||||||
|
|
||||||
|
This error occurs when **two or more clients use the same session**,
|
||||||
|
that is, when you write the same session name to be used in the client:
|
||||||
|
|
||||||
|
* You have an older process using the same session file.
|
||||||
|
* You have two different scripts running (interactive sessions count too).
|
||||||
|
* You have two clients in the same script running at the same time.
|
||||||
|
|
||||||
|
The solution is, if you need two clients, use two sessions. If the
|
||||||
|
problem persists and you're on Linux, you can use ``fuser my.session``
|
||||||
|
to find out the process locking the file. As a last resort, you can
|
||||||
|
reboot your system.
|
||||||
|
|
||||||
|
If you really dislike SQLite, use a different session storage. There
|
||||||
|
is an entire section covering that at :ref:`sessions`.
|
||||||
|
|
||||||
|
|
||||||
|
event.chat or event.sender is None
|
||||||
|
==================================
|
||||||
|
|
||||||
|
Telegram doesn't always send this information in order to save bandwidth.
|
||||||
|
If you need the information, you should fetch it yourself, since the library
|
||||||
|
won't do unnecessary work unless you need to:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
async def handler(event):
|
||||||
|
chat = await event.get_chat()
|
||||||
|
sender = await event.get_sender()
|
||||||
|
|
||||||
|
|
||||||
|
Can I use Flask with the library?
|
||||||
|
=================================
|
||||||
|
|
||||||
|
Yes, if you know what you are doing. However, you will probably have a
|
||||||
|
lot of headaches to get threads and asyncio to work together. Instead,
|
||||||
|
consider using `Quart <https://pgjones.gitlab.io/quart/>`_, an asyncio-based
|
||||||
|
alternative to `Flask <flask.pocoo.org/>`_.
|
||||||
|
|
||||||
|
.. _logging: https://docs.python.org/3/library/logging.html
|
||||||
|
.. _@SpamBot: https://t.me/SpamBot
|
||||||
|
.. _issue 297: https://github.com/LonamiWebs/Telethon/issues/297
|
|
@ -1,191 +1,16 @@
|
||||||
.. _ref-summary:
|
|
||||||
|
|
||||||
=================
|
=================
|
||||||
Reference Summary
|
Objects Reference
|
||||||
=================
|
=================
|
||||||
|
|
||||||
This page contains a summary of all the important methods and properties that
|
This is the quick reference for those objects returned by client methods
|
||||||
you may need when using Telethon. They are sorted by relevance and are not in
|
or other useful modules that the library has to offer. They are kept in
|
||||||
alphabetical order.
|
a separate page to help finding and discovering them.
|
||||||
|
|
||||||
The way you should use this page is by looking up the type you need in the
|
Remember that this page only shows properties and methods,
|
||||||
table of contents (method index below) and searching for the method or
|
**not attributes**. Make sure to open the full documentation
|
||||||
property that you are interested in.
|
to find out about the attributes.
|
||||||
|
|
||||||
.. contents:: Method Index
|
.. contents::
|
||||||
|
|
||||||
TelegramClient
|
|
||||||
==============
|
|
||||||
|
|
||||||
This is a summary of the methods and
|
|
||||||
properties you will find at :ref:`telethon-client`.
|
|
||||||
|
|
||||||
Auth
|
|
||||||
----
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.auth.AuthMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
start
|
|
||||||
send_code_request
|
|
||||||
sign_in
|
|
||||||
sign_up
|
|
||||||
log_out
|
|
||||||
edit_2fa
|
|
||||||
|
|
||||||
Base
|
|
||||||
----
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.telegrambaseclient.TelegramBaseClient
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
connect
|
|
||||||
disconnect
|
|
||||||
is_connected
|
|
||||||
disconnected
|
|
||||||
loop
|
|
||||||
|
|
||||||
Messages
|
|
||||||
--------
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.messages.MessageMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
send_message
|
|
||||||
edit_message
|
|
||||||
delete_messages
|
|
||||||
forward_messages
|
|
||||||
iter_messages
|
|
||||||
get_messages
|
|
||||||
send_read_acknowledge
|
|
||||||
|
|
||||||
Uploads
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.uploads.UploadMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
send_file
|
|
||||||
upload_file
|
|
||||||
|
|
||||||
Downloads
|
|
||||||
---------
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.downloads.DownloadMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
download_media
|
|
||||||
download_profile_photo
|
|
||||||
download_file
|
|
||||||
|
|
||||||
Dialogs
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.dialogs.DialogMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
iter_dialogs
|
|
||||||
get_dialogs
|
|
||||||
iter_drafts
|
|
||||||
get_drafts
|
|
||||||
conversation
|
|
||||||
|
|
||||||
Users
|
|
||||||
-----
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.users.UserMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
get_me
|
|
||||||
is_bot
|
|
||||||
is_user_authorized
|
|
||||||
get_entity
|
|
||||||
get_input_entity
|
|
||||||
get_peer_id
|
|
||||||
|
|
||||||
Chats
|
|
||||||
-----
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.chats.ChatMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
iter_participants
|
|
||||||
get_participants
|
|
||||||
iter_admin_log
|
|
||||||
get_admin_log
|
|
||||||
action
|
|
||||||
|
|
||||||
Parse Mode
|
|
||||||
----------
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.messageparse.MessageParseMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
parse_mode
|
|
||||||
|
|
||||||
Updates
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. py:currentmodule:: telethon.client.updates.UpdateMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
on
|
|
||||||
run_until_disconnected
|
|
||||||
add_event_handler
|
|
||||||
remove_event_handler
|
|
||||||
list_event_handlers
|
|
||||||
catch_up
|
|
||||||
|
|
||||||
Bots
|
|
||||||
----
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.bots.BotMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
inline_query
|
|
||||||
|
|
||||||
Buttons
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.buttons.ButtonMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
build_reply_markup
|
|
||||||
|
|
||||||
Account
|
|
||||||
-------
|
|
||||||
|
|
||||||
.. currentmodule:: telethon.client.account.AccountMethods
|
|
||||||
|
|
||||||
.. autosummary::
|
|
||||||
:nosignatures:
|
|
||||||
|
|
||||||
takeout
|
|
||||||
end_takeout
|
|
||||||
|
|
||||||
|
|
||||||
Message
|
Message
|
|
@ -1,22 +0,0 @@
|
||||||
.. _telethon-errors-package:
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.errors package
|
|
||||||
========================
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.errors\.common module
|
|
||||||
-------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.errors.common
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.errors\.rpcbaseerrors module
|
|
||||||
--------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.errors.rpcbaseerrors
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
|
@ -1,27 +0,0 @@
|
||||||
telethon\.extensions package
|
|
||||||
============================
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.extensions\.binaryreader module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.extensions.binaryreader
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.extensions\.markdown module
|
|
||||||
-------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.extensions.markdown
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.extensions\.html module
|
|
||||||
---------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.extensions.html
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
|
@ -1,35 +0,0 @@
|
||||||
telethon\.network package
|
|
||||||
=========================
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.network\.connection module
|
|
||||||
------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.network.connection
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.network\.mtprotoplainsender module
|
|
||||||
------------------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.network.mtprotoplainsender
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.network\.mtprotosender module
|
|
||||||
-----------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.network.mtprotosender
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.network\.authenticator module
|
|
||||||
---------------------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.network.authenticator
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
|
@ -1,90 +0,0 @@
|
||||||
.. _telethon-package:
|
|
||||||
|
|
||||||
|
|
||||||
telethon package
|
|
||||||
================
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.client module
|
|
||||||
-----------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.client
|
|
||||||
|
|
||||||
.. automodule:: telethon.client
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.utils module
|
|
||||||
----------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.utils
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.helpers module
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.helpers
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.events package
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.events
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.sessions module
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.sessions
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
||||||
|
|
||||||
telethon\.errors package
|
|
||||||
------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.errors
|
|
||||||
|
|
||||||
telethon\.extensions package
|
|
||||||
----------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.extensions
|
|
||||||
|
|
||||||
telethon\.network package
|
|
||||||
-------------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.network
|
|
||||||
|
|
||||||
telethon\.tl package
|
|
||||||
--------------------
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.tl
|
|
||||||
|
|
||||||
|
|
||||||
Module contents
|
|
||||||
---------------
|
|
||||||
|
|
||||||
.. automodule:: telethon
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
|
@ -1,16 +0,0 @@
|
||||||
telethon\.tl\.custom package
|
|
||||||
============================
|
|
||||||
|
|
||||||
|
|
||||||
.. toctree::
|
|
||||||
|
|
||||||
telethon.tl.custom
|
|
||||||
|
|
||||||
|
|
||||||
telethon\.tl\.tlobject module
|
|
||||||
-----------------------------
|
|
||||||
|
|
||||||
.. automodule:: telethon.tl.tlobject
|
|
||||||
:members:
|
|
||||||
:undoc-members:
|
|
||||||
:show-inheritance:
|
|
|
@ -120,7 +120,7 @@ class AccountMethods(UserMethods):
|
||||||
files: bool = None,
|
files: bool = None,
|
||||||
max_file_size: bool = None) -> 'TelegramClient':
|
max_file_size: bool = None) -> 'TelegramClient':
|
||||||
"""
|
"""
|
||||||
Returns a :ref:`TelegramClient` which calls methods behind a takeout session.
|
Returns a :ref:`telethon-client` which calls methods behind a takeout session.
|
||||||
|
|
||||||
It does so by creating a proxy object over the current client through
|
It does so by creating a proxy object over the current client through
|
||||||
which making requests will use :tl:`InvokeWithTakeoutRequest` to wrap
|
which making requests will use :tl:`InvokeWithTakeoutRequest` to wrap
|
||||||
|
@ -190,6 +190,20 @@ class AccountMethods(UserMethods):
|
||||||
max_file_size (`int`):
|
max_file_size (`int`):
|
||||||
The maximum file size, in bytes, that you plan
|
The maximum file size, in bytes, that you plan
|
||||||
to download for each message with media.
|
to download for each message with media.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import errors
|
||||||
|
|
||||||
|
try:
|
||||||
|
with client.takeout() as takeout:
|
||||||
|
for message in takeout.iter_messages(chat, wait_time=0):
|
||||||
|
... # Do something with the message
|
||||||
|
|
||||||
|
except errors.TakeoutInitDelayError as e:
|
||||||
|
print('Must wait', e.seconds, 'before takeout')
|
||||||
"""
|
"""
|
||||||
request_kwargs = dict(
|
request_kwargs = dict(
|
||||||
contacts=contacts,
|
contacts=contacts,
|
||||||
|
|
|
@ -40,13 +40,6 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
||||||
will be banned otherwise.** See https://telegram.org/tos
|
will be banned otherwise.** See https://telegram.org/tos
|
||||||
and https://core.telegram.org/api/terms.
|
and https://core.telegram.org/api/terms.
|
||||||
|
|
||||||
Example usage:
|
|
||||||
>>> client = ...
|
|
||||||
>>> client.start(phone)
|
|
||||||
Please enter the code you received: 12345
|
|
||||||
Please enter your password: *******
|
|
||||||
(You are now logged in)
|
|
||||||
|
|
||||||
If the event loop is already running, this method returns a
|
If the event loop is already running, this method returns a
|
||||||
coroutine that you should await on your own code; otherwise
|
coroutine that you should await on your own code; otherwise
|
||||||
the loop is ran until said coroutine completes.
|
the loop is ran until said coroutine completes.
|
||||||
|
@ -91,6 +84,24 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
||||||
Returns:
|
Returns:
|
||||||
This `TelegramClient`, so initialization
|
This `TelegramClient`, so initialization
|
||||||
can be chained with ``.start()``.
|
can be chained with ``.start()``.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client = TelegramClient('anon', api_id, api_hash)
|
||||||
|
|
||||||
|
# Starting as a bot account
|
||||||
|
client.start(bot_token=bot_token)
|
||||||
|
|
||||||
|
# Starting as an user account
|
||||||
|
client.start(phone)
|
||||||
|
# Please enter the code you received: 12345
|
||||||
|
# Please enter your password: *******
|
||||||
|
# (You are now logged in)
|
||||||
|
|
||||||
|
# Starting using a context manager (this calls start()):
|
||||||
|
with client:
|
||||||
|
pass
|
||||||
"""
|
"""
|
||||||
if code_callback is None:
|
if code_callback is None:
|
||||||
def code_callback():
|
def code_callback():
|
||||||
|
@ -452,6 +463,13 @@ class AuthMethods(MessageParseMethods, UserMethods):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
``True`` if the operation was successful.
|
``True`` if the operation was successful.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Note: you will need to login again!
|
||||||
|
client.log_out()
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
await self(functions.auth.LogOutRequest())
|
await self(functions.auth.LogOutRequest())
|
||||||
|
|
|
@ -39,6 +39,16 @@ class BotMethods(UserMethods):
|
||||||
Returns:
|
Returns:
|
||||||
A list of `custom.InlineResult
|
A list of `custom.InlineResult
|
||||||
<telethon.tl.custom.inlineresult.InlineResult>`.
|
<telethon.tl.custom.inlineresult.InlineResult>`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Make an inline query to @like
|
||||||
|
results = client.inline_query('like', 'Do you like Telethon?')
|
||||||
|
|
||||||
|
# Send the first result to some chat
|
||||||
|
message = results[0].click('TelethonOffTopic')
|
||||||
"""
|
"""
|
||||||
bot = await self.get_input_entity(bot)
|
bot = await self.get_input_entity(bot)
|
||||||
result = await self(functions.messages.GetInlineBotResultsRequest(
|
result = await self(functions.messages.GetInlineBotResultsRequest(
|
||||||
|
|
|
@ -328,6 +328,23 @@ class ChatMethods(UserMethods):
|
||||||
with an additional ``.participant`` attribute which is the
|
with an additional ``.participant`` attribute which is the
|
||||||
matched :tl:`ChannelParticipant` type for channels/megagroups
|
matched :tl:`ChannelParticipant` type for channels/megagroups
|
||||||
or :tl:`ChatParticipants` for normal chats.
|
or :tl:`ChatParticipants` for normal chats.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Show all user IDs in a chat
|
||||||
|
for user in client.iter_participants(chat):
|
||||||
|
print(user.id)
|
||||||
|
|
||||||
|
# Search by name
|
||||||
|
for user in client.iter_participants(chat, search='name'):
|
||||||
|
print(user.username)
|
||||||
|
|
||||||
|
# Filter by admins
|
||||||
|
from telethon.tl.types import ChannelParticipantsAdmins
|
||||||
|
for user in client.iter_participants(chat, filter=ChannelParticipantsAdmins):
|
||||||
|
print(user.first_name)
|
||||||
"""
|
"""
|
||||||
return _ParticipantsIter(
|
return _ParticipantsIter(
|
||||||
self,
|
self,
|
||||||
|
@ -343,7 +360,7 @@ class ChatMethods(UserMethods):
|
||||||
*args,
|
*args,
|
||||||
**kwargs) -> 'hints.TotalList':
|
**kwargs) -> 'hints.TotalList':
|
||||||
"""
|
"""
|
||||||
Same as `iter_participants`, but returns a
|
Same as `iter_participants()`, but returns a
|
||||||
`TotalList <telethon.helpers.TotalList>` instead.
|
`TotalList <telethon.helpers.TotalList>` instead.
|
||||||
"""
|
"""
|
||||||
return await self.iter_participants(*args, **kwargs).collect()
|
return await self.iter_participants(*args, **kwargs).collect()
|
||||||
|
@ -457,6 +474,20 @@ class ChatMethods(UserMethods):
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
Instances of `telethon.tl.custom.adminlogevent.AdminLogEvent`.
|
Instances of `telethon.tl.custom.adminlogevent.AdminLogEvent`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
for event in client.iter_admin_log(channel):
|
||||||
|
if event.changed_title:
|
||||||
|
print('The title changed from', event.old, 'to', event.new)
|
||||||
|
|
||||||
|
# Get a list of deleted message events which said "heck"
|
||||||
|
events = client.get_admin_log(channel, search='heck', delete=True)
|
||||||
|
|
||||||
|
# Print the old message before it was deleted
|
||||||
|
print(events[0].old)
|
||||||
"""
|
"""
|
||||||
return _AdminLogIter(
|
return _AdminLogIter(
|
||||||
self,
|
self,
|
||||||
|
@ -487,7 +518,7 @@ class ChatMethods(UserMethods):
|
||||||
*args,
|
*args,
|
||||||
**kwargs) -> 'hints.TotalList':
|
**kwargs) -> 'hints.TotalList':
|
||||||
"""
|
"""
|
||||||
Same as `iter_admin_log`, but returns a ``list`` instead.
|
Same as `iter_admin_log()`, but returns a ``list`` instead.
|
||||||
"""
|
"""
|
||||||
return await self.iter_admin_log(*args, **kwargs).collect()
|
return await self.iter_admin_log(*args, **kwargs).collect()
|
||||||
|
|
||||||
|
|
|
@ -138,6 +138,21 @@ class DialogMethods(UserMethods):
|
||||||
|
|
||||||
Yields:
|
Yields:
|
||||||
Instances of `telethon.tl.custom.dialog.Dialog`.
|
Instances of `telethon.tl.custom.dialog.Dialog`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Get all open conversation, print the title of the first
|
||||||
|
dialogs = client.get_dialogs()
|
||||||
|
first = dialogs[0]
|
||||||
|
print(first.title)
|
||||||
|
|
||||||
|
# Use the dialog somewhere else
|
||||||
|
client.send_message(first, 'hi')
|
||||||
|
|
||||||
|
# Get drafts
|
||||||
|
drafts = client.get_drafts()
|
||||||
"""
|
"""
|
||||||
return _DialogsIter(
|
return _DialogsIter(
|
||||||
self,
|
self,
|
||||||
|
@ -150,7 +165,7 @@ class DialogMethods(UserMethods):
|
||||||
|
|
||||||
async def get_dialogs(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
|
async def get_dialogs(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
|
||||||
"""
|
"""
|
||||||
Same as `iter_dialogs`, but returns a
|
Same as `iter_dialogs()`, but returns a
|
||||||
`TotalList <telethon.helpers.TotalList>` instead.
|
`TotalList <telethon.helpers.TotalList>` instead.
|
||||||
"""
|
"""
|
||||||
return await self.iter_dialogs(*args, **kwargs).collect()
|
return await self.iter_dialogs(*args, **kwargs).collect()
|
||||||
|
@ -169,7 +184,7 @@ class DialogMethods(UserMethods):
|
||||||
|
|
||||||
async def get_drafts(self: 'TelegramClient') -> 'hints.TotalList':
|
async def get_drafts(self: 'TelegramClient') -> 'hints.TotalList':
|
||||||
"""
|
"""
|
||||||
Same as :meth:`iter_drafts`, but returns a list instead.
|
Same as `iter_drafts()`, but returns a list instead.
|
||||||
"""
|
"""
|
||||||
return await self.iter_drafts().collect()
|
return await self.iter_drafts().collect()
|
||||||
|
|
||||||
|
@ -257,6 +272,35 @@ class DialogMethods(UserMethods):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
A `Conversation <telethon.tl.custom.conversation.Conversation>`.
|
A `Conversation <telethon.tl.custom.conversation.Conversation>`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# <you> denotes outgoing messages you sent
|
||||||
|
# <usr> denotes incoming response messages
|
||||||
|
with bot.conversation(chat) as conv:
|
||||||
|
# <you> Hi!
|
||||||
|
conv.send_message('Hi!')
|
||||||
|
|
||||||
|
# <usr> Hello!
|
||||||
|
hello = conv.get_response()
|
||||||
|
|
||||||
|
# <you> Please tell me your name
|
||||||
|
conv.send_message('Please tell me your name')
|
||||||
|
|
||||||
|
# <usr> ?
|
||||||
|
name = conv.get_response().raw_text
|
||||||
|
|
||||||
|
while not any(x.isalpha() for x in name):
|
||||||
|
# <you> Your name didn't have any letters! Try again
|
||||||
|
conv.send_message("Your name didn't have any letters! Try again")
|
||||||
|
|
||||||
|
# <usr> Lonami
|
||||||
|
name = conv.get_response().raw_text
|
||||||
|
|
||||||
|
# <you> Thanks Lonami!
|
||||||
|
conv.send_message('Thanks {}!'.format(name))
|
||||||
"""
|
"""
|
||||||
return custom.Conversation(
|
return custom.Conversation(
|
||||||
self,
|
self,
|
||||||
|
|
|
@ -56,6 +56,13 @@ class DownloadMethods(UserMethods):
|
||||||
Returns:
|
Returns:
|
||||||
``None`` if no photo was provided, or if it was Empty. On success
|
``None`` if no photo was provided, or if it was Empty. On success
|
||||||
the file path is returned since it may differ from the one given.
|
the file path is returned since it may differ from the one given.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
path = client.download_profile_photo('me')
|
||||||
|
print(path)
|
||||||
"""
|
"""
|
||||||
# hex(crc32(x.encode('ascii'))) for x in
|
# hex(crc32(x.encode('ascii'))) for x in
|
||||||
# ('User', 'Chat', 'UserFull', 'ChatFull')
|
# ('User', 'Chat', 'UserFull', 'ChatFull')
|
||||||
|
@ -173,6 +180,17 @@ class DownloadMethods(UserMethods):
|
||||||
Returns:
|
Returns:
|
||||||
``None`` if no media was provided, or if it was Empty. On success
|
``None`` if no media was provided, or if it was Empty. On success
|
||||||
the file path is returned since it may differ from the one given.
|
the file path is returned since it may differ from the one given.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
path = client.download_media(message)
|
||||||
|
client.download_media(message, filename)
|
||||||
|
# or
|
||||||
|
path = message.download_media()
|
||||||
|
message.download_media(filename)
|
||||||
|
|
||||||
"""
|
"""
|
||||||
# TODO This won't work for messageService
|
# TODO This won't work for messageService
|
||||||
if isinstance(message, types.Message):
|
if isinstance(message, types.Message):
|
||||||
|
|
|
@ -413,6 +413,31 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
Telegram's flood wait limit for :tl:`GetHistoryRequest` seems to
|
Telegram's flood wait limit for :tl:`GetHistoryRequest` seems to
|
||||||
be around 30 seconds per 10 requests, therefore a sleep of 1
|
be around 30 seconds per 10 requests, therefore a sleep of 1
|
||||||
second is the default for this limit (or above).
|
second is the default for this limit (or above).
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# From most-recent to oldest
|
||||||
|
for message in client.iter_messages(chat):
|
||||||
|
print(message.id, message.text)
|
||||||
|
|
||||||
|
# From oldest to most-recent
|
||||||
|
for message in client.iter_messages(chat, reverse=True):
|
||||||
|
print(message.id, message.text)
|
||||||
|
|
||||||
|
# Filter by sender
|
||||||
|
for message in client.iter_messages(chat, from_user='me'):
|
||||||
|
print(message.text)
|
||||||
|
|
||||||
|
# Server-side search with fuzzy text
|
||||||
|
for message in client.iter_messages(chat, search='hello'):
|
||||||
|
print(message.id)
|
||||||
|
|
||||||
|
# Filter by message type:
|
||||||
|
from telethon.tl.types import InputMessagesFilterPhotos
|
||||||
|
for message in client.iter_messages(chat, filter=InputMessagesFilterPhotos):
|
||||||
|
print(message.photo)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if ids is not None:
|
if ids is not None:
|
||||||
|
@ -436,7 +461,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
|
|
||||||
async def get_messages(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
|
async def get_messages(self: 'TelegramClient', *args, **kwargs) -> 'hints.TotalList':
|
||||||
"""
|
"""
|
||||||
Same as `iter_messages`, but returns a
|
Same as `iter_messages()`, but returns a
|
||||||
`TotalList <telethon.helpers.TotalList>` instead.
|
`TotalList <telethon.helpers.TotalList>` instead.
|
||||||
|
|
||||||
If the `limit` is not set, it will be 1 by default unless both
|
If the `limit` is not set, it will be 1 by default unless both
|
||||||
|
@ -450,6 +475,21 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
If `ids` is present in the *named* arguments and is not a list,
|
If `ids` is present in the *named* arguments and is not a list,
|
||||||
a single `Message <telethon.tl.custom.message.Message>` will be
|
a single `Message <telethon.tl.custom.message.Message>` will be
|
||||||
returned for convenience instead of a list.
|
returned for convenience instead of a list.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Get 0 photos and print the total to show how many photos there are
|
||||||
|
from telethon.tl.types import InputMessagesFilterPhotos
|
||||||
|
photos = client.get_messages(chat, 0, filter=InputMessagesFilterPhotos)
|
||||||
|
print(photos.total)
|
||||||
|
|
||||||
|
# Get all the photos
|
||||||
|
photos = client.get_messages(chat, None, filter=InputMessagesFilterPhotos)
|
||||||
|
|
||||||
|
# Get messages by ID:
|
||||||
|
message_1337 = client.get_messages(chats, ids=1337)
|
||||||
"""
|
"""
|
||||||
if len(args) == 1 and 'limit' not in kwargs:
|
if len(args) == 1 and 'limit' not in kwargs:
|
||||||
if 'min_id' in kwargs and 'max_id' in kwargs:
|
if 'min_id' in kwargs and 'max_id' in kwargs:
|
||||||
|
@ -501,6 +541,7 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
the bot.
|
the bot.
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
|
||||||
entity (`entity`):
|
entity (`entity`):
|
||||||
To who will it be sent.
|
To who will it be sent.
|
||||||
|
|
||||||
|
@ -556,7 +597,65 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
notify them. Set it to ``True`` to alter this behaviour.
|
notify them. Set it to ``True`` to alter this behaviour.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
|
|
||||||
The sent `custom.Message <telethon.tl.custom.message.Message>`.
|
The sent `custom.Message <telethon.tl.custom.message.Message>`.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client.send_message('lonami', 'Thanks for the Telethon library!')
|
||||||
|
|
||||||
|
# Replies and responses
|
||||||
|
message = client.send_message('me', 'Trying out **markdown**')
|
||||||
|
message.reply('Trying replies')
|
||||||
|
message.respond('Trying responses')
|
||||||
|
|
||||||
|
# Default to another parse mode
|
||||||
|
client.parse_mode = 'html'
|
||||||
|
|
||||||
|
client.send_message('me', 'Some <b>bold</b> and <i>italic</i> text')
|
||||||
|
client.send_message('me', 'An <a href="https://example.com">URL</a>')
|
||||||
|
client.send_message('me', '<code>code</code> and <pre>pre\nblocks</pre>')
|
||||||
|
client.send_message('me', '<a href="tg://user?id=me">Mentions</a>')
|
||||||
|
|
||||||
|
# Explicit parse mode
|
||||||
|
# No parse mode by default
|
||||||
|
client.parse_mode = None
|
||||||
|
|
||||||
|
# ...but here I want markdown
|
||||||
|
client.send_message('me', 'Hello, **world**!', parse_mode='md')
|
||||||
|
|
||||||
|
# ...and here I need HTML
|
||||||
|
client.send_message('me', 'Hello, <i>world</i>!', parse_mode='html')
|
||||||
|
|
||||||
|
# If you logged in as a bot account, you can send buttons
|
||||||
|
from telethon import events, Button
|
||||||
|
|
||||||
|
@client.on(events.CallbackQuery)
|
||||||
|
async def callback(event):
|
||||||
|
await event.edit('Thank you for clicking {}!'.format(event.data))
|
||||||
|
|
||||||
|
# Single inline button
|
||||||
|
client.send_message(chat, 'A single button, with "clk1" as data',
|
||||||
|
buttons=Button.inline('Click me', b'clk1'))
|
||||||
|
|
||||||
|
# Matrix of inline buttons
|
||||||
|
client.send_message(chat, 'Pick one from this grid', buttons=[
|
||||||
|
[Button.inline('Left'), Button.inline('Right')],
|
||||||
|
[Button.url('Check this site!', 'https://lonamiwebs.github.io')]
|
||||||
|
])
|
||||||
|
|
||||||
|
# Reply keyboard
|
||||||
|
client.send_message(chat, 'Welcome', buttons=[
|
||||||
|
Button.text('Thanks!', resize=True, single_use=True),
|
||||||
|
Button.request_phone('Send phone'),
|
||||||
|
Button.request_location('Send location')
|
||||||
|
])
|
||||||
|
|
||||||
|
# Forcing replies or clearing buttons.
|
||||||
|
client.send_message(chat, 'Reply to me', buttons=Button.force_reply())
|
||||||
|
client.send_message(chat, 'Bye Keyboard!', buttons=Button.clear())
|
||||||
"""
|
"""
|
||||||
if file is not None:
|
if file is not None:
|
||||||
return await self.send_file(
|
return await self.send_file(
|
||||||
|
@ -685,6 +784,25 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
Note that if all messages are invalid (i.e. deleted) the call
|
Note that if all messages are invalid (i.e. deleted) the call
|
||||||
will fail with ``MessageIdInvalidError``. If only some are
|
will fail with ``MessageIdInvalidError``. If only some are
|
||||||
invalid, the list will have ``None`` instead of those messages.
|
invalid, the list will have ``None`` instead of those messages.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# a single one
|
||||||
|
client.forward_messages(chat, message)
|
||||||
|
# or
|
||||||
|
client.forward_messages(chat, message_id, from_chat)
|
||||||
|
# or
|
||||||
|
message.forward_to(chat)
|
||||||
|
|
||||||
|
# multiple
|
||||||
|
client.forward_messages(chat, messages)
|
||||||
|
# or
|
||||||
|
client.forward_messages(chat, message_ids, from_chat)
|
||||||
|
|
||||||
|
# Forwarding as a copy
|
||||||
|
client.send_message(chat, message)
|
||||||
"""
|
"""
|
||||||
single = not utils.is_list_like(messages)
|
single = not utils.is_list_like(messages)
|
||||||
if single:
|
if single:
|
||||||
|
@ -829,6 +947,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
The edited `telethon.tl.custom.message.Message`, unless
|
The edited `telethon.tl.custom.message.Message`, unless
|
||||||
`entity` was a :tl:`InputBotInlineMessageID` in which
|
`entity` was a :tl:`InputBotInlineMessageID` in which
|
||||||
case this method returns a boolean.
|
case this method returns a boolean.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client.edit_message(message, 'New text')
|
||||||
|
# or
|
||||||
|
message.edit('New text')
|
||||||
|
# or
|
||||||
|
client.edit_message(chat, message_id, 'New text')
|
||||||
"""
|
"""
|
||||||
if isinstance(entity, types.InputBotInlineMessageID):
|
if isinstance(entity, types.InputBotInlineMessageID):
|
||||||
text = message
|
text = message
|
||||||
|
@ -900,6 +1028,14 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
Returns:
|
Returns:
|
||||||
A list of :tl:`AffectedMessages`, each item being the result
|
A list of :tl:`AffectedMessages`, each item being the result
|
||||||
for the delete calls of the messages in chunks of 100 each.
|
for the delete calls of the messages in chunks of 100 each.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client.delete_messages(chat, messages)
|
||||||
|
# or
|
||||||
|
message.delete()
|
||||||
"""
|
"""
|
||||||
if not utils.is_list_like(message_ids):
|
if not utils.is_list_like(message_ids):
|
||||||
message_ids = (message_ids,)
|
message_ids = (message_ids,)
|
||||||
|
@ -955,6 +1091,16 @@ class MessageMethods(UploadMethods, ButtonMethods, MessageParseMethods):
|
||||||
|
|
||||||
If no message is provided, this will be the only action
|
If no message is provided, this will be the only action
|
||||||
taken.
|
taken.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
client.send_read_acknowledge(last_message)
|
||||||
|
# or
|
||||||
|
client.send_read_acknowledge(last_message_id)
|
||||||
|
# or
|
||||||
|
client.send_read_acknowledge(messages)
|
||||||
"""
|
"""
|
||||||
if max_id is None:
|
if max_id is None:
|
||||||
if not message:
|
if not message:
|
||||||
|
|
|
@ -396,6 +396,13 @@ class TelegramBaseClient(abc.ABC):
|
||||||
If the event loop is already running, this method returns a
|
If the event loop is already running, this method returns a
|
||||||
coroutine that you should await on your own code; otherwise
|
coroutine that you should await on your own code; otherwise
|
||||||
the loop is ran until said coroutine completes.
|
the loop is ran until said coroutine completes.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# You don't need to use this if you used "with client"
|
||||||
|
client.disconnect()
|
||||||
"""
|
"""
|
||||||
if self._loop.is_running():
|
if self._loop.is_running():
|
||||||
return self._disconnect_coro()
|
return self._disconnect_coro()
|
||||||
|
|
|
@ -117,7 +117,7 @@ class UpdateMethods(UserMethods):
|
||||||
callback: callable,
|
callback: callable,
|
||||||
event: EventBuilder = None) -> int:
|
event: EventBuilder = None) -> int:
|
||||||
"""
|
"""
|
||||||
Inverse operation of `add_event_handler`.
|
Inverse operation of `add_event_handler()`.
|
||||||
|
|
||||||
If no event is given, all events for this callback are removed.
|
If no event is given, all events for this callback are removed.
|
||||||
Returns how many callbacks were removed.
|
Returns how many callbacks were removed.
|
||||||
|
|
|
@ -232,6 +232,32 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||||
Returns:
|
Returns:
|
||||||
The `telethon.tl.custom.message.Message` (or messages) containing
|
The `telethon.tl.custom.message.Message` (or messages) containing
|
||||||
the sent file, or messages if a list of them was passed.
|
the sent file, or messages if a list of them was passed.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Normal files like photos
|
||||||
|
client.send_file(chat, '/my/photos/me.jpg', caption="It's me!")
|
||||||
|
# or
|
||||||
|
client.send_message(chat, "It's me!", file='/my/photos/me.jpg')
|
||||||
|
|
||||||
|
# Voice notes or round videos
|
||||||
|
client.send_file(chat, '/my/songs/song.mp3', voice_note=True)
|
||||||
|
client.send_file(chat, '/my/videos/video.mp4', video_note=True)
|
||||||
|
|
||||||
|
# Custom thumbnails
|
||||||
|
client.send_file(chat, '/my/documents/doc.txt', thumb='photo.jpg')
|
||||||
|
|
||||||
|
# Only documents
|
||||||
|
client.send_file(chat, '/my/photos/photo.png', force_document=True)
|
||||||
|
|
||||||
|
# Albums
|
||||||
|
client.send_file(chat, [
|
||||||
|
'/my/photos/holiday1.jpg',
|
||||||
|
'/my/photos/holiday2.jpg',
|
||||||
|
'/my/drawings/portrait.png'
|
||||||
|
])
|
||||||
"""
|
"""
|
||||||
# i.e. ``None`` was used
|
# i.e. ``None`` was used
|
||||||
if not file:
|
if not file:
|
||||||
|
@ -427,6 +453,23 @@ class UploadMethods(ButtonMethods, MessageParseMethods, UserMethods):
|
||||||
:tl:`InputFileBig` if the file size is larger than 10MB,
|
:tl:`InputFileBig` if the file size is larger than 10MB,
|
||||||
`telethon.tl.custom.inputsizedfile.InputSizedFile`
|
`telethon.tl.custom.inputsizedfile.InputSizedFile`
|
||||||
(subclass of :tl:`InputFile`) otherwise.
|
(subclass of :tl:`InputFile`) otherwise.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Photos as photo and document
|
||||||
|
file = client.upload_file('photo.jpg')
|
||||||
|
client.send_file(chat, file) # sends as photo
|
||||||
|
client.send_file(chat, file, force_document=True) # sends as document
|
||||||
|
|
||||||
|
file.name = 'not a photo.jpg'
|
||||||
|
client.send_file(chat, file, force_document=True) # document, new name
|
||||||
|
|
||||||
|
# As song or as voice note
|
||||||
|
file = client.upload_file('song.ogg')
|
||||||
|
client.send_file(chat, file) # sends as song
|
||||||
|
client.send_file(chat, file, voice_note=True) # sends as voice note
|
||||||
"""
|
"""
|
||||||
if isinstance(file, (types.InputFile, types.InputFileBig)):
|
if isinstance(file, (types.InputFile, types.InputFileBig)):
|
||||||
return file # Already uploaded
|
return file # Already uploaded
|
||||||
|
|
|
@ -191,6 +191,27 @@ class UserMethods(TelegramBaseClient):
|
||||||
Returns:
|
Returns:
|
||||||
:tl:`User`, :tl:`Chat` or :tl:`Channel` corresponding to the
|
:tl:`User`, :tl:`Chat` or :tl:`Channel` corresponding to the
|
||||||
input entity. A list will be returned if more than one was given.
|
input entity. A list will be returned if more than one was given.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from telethon import utils
|
||||||
|
|
||||||
|
me = client.get_entity('me')
|
||||||
|
print(utils.get_display_name(me))
|
||||||
|
|
||||||
|
chat = client.get_input_entity('username')
|
||||||
|
for message in client.iter_messages(chat):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Note that you could have used the username directly, but it's
|
||||||
|
# good to use get_input_entity if you will reuse it a lot.
|
||||||
|
for message in client.iter_messages('username'):
|
||||||
|
...
|
||||||
|
|
||||||
|
# Note that for this to work the phone number must be in your contacts
|
||||||
|
some_id = client.get_peer_id('+34123456789')
|
||||||
"""
|
"""
|
||||||
single = not utils.is_list_like(entity)
|
single = not utils.is_list_like(entity)
|
||||||
if single:
|
if single:
|
||||||
|
|
|
@ -42,7 +42,7 @@ class StopPropagation(Exception):
|
||||||
def register(event=None):
|
def register(event=None):
|
||||||
"""
|
"""
|
||||||
Decorator method to *register* event handlers. This is the client-less
|
Decorator method to *register* event handlers. This is the client-less
|
||||||
`add_event_handler
|
`add_event_handler()
|
||||||
<telethon.client.updates.UpdateMethods.add_event_handler>` variant.
|
<telethon.client.updates.UpdateMethods.add_event_handler>` variant.
|
||||||
|
|
||||||
Note that this method only registers callbacks as handlers,
|
Note that this method only registers callbacks as handlers,
|
||||||
|
|
|
@ -178,6 +178,20 @@ class InlineQuery(EventBuilder):
|
||||||
switch_pm_param (`str`, optional):
|
switch_pm_param (`str`, optional):
|
||||||
Optional parameter to start the bot with if
|
Optional parameter to start the bot with if
|
||||||
`switch_pm` was used.
|
`switch_pm` was used.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
@bot.on(events.InlineQuery)
|
||||||
|
async def handler(event):
|
||||||
|
builder = event.builder
|
||||||
|
|
||||||
|
rev_text = event.text[::-1]
|
||||||
|
await event.answer([
|
||||||
|
builder.article('Reverse text', text=rev_text),
|
||||||
|
builder.photo('/path/to/photo.jpg')
|
||||||
|
])
|
||||||
"""
|
"""
|
||||||
if self._answered:
|
if self._answered:
|
||||||
return
|
return
|
||||||
|
|
|
@ -95,7 +95,7 @@ class MessageRead(EventBuilder):
|
||||||
|
|
||||||
async def get_messages(self):
|
async def get_messages(self):
|
||||||
"""
|
"""
|
||||||
Returns the list of `telethon.tl.custom.message.Message`
|
Returns the list of `Message <telethon.tl.custom.message.Message>`
|
||||||
**which contents'** were read.
|
**which contents'** were read.
|
||||||
|
|
||||||
Use :meth:`is_read` if you need to check whether a message
|
Use :meth:`is_read` if you need to check whether a message
|
||||||
|
|
|
@ -190,23 +190,23 @@ class UserUpdate(EventBuilder):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user(self):
|
def user(self):
|
||||||
"""Alias for `sender`."""
|
"""Alias for `sender <telethon.tl.custom.sendergetter.SenderGetter.sender>`."""
|
||||||
return self.sender
|
return self.sender
|
||||||
|
|
||||||
async def get_user(self):
|
async def get_user(self):
|
||||||
"""Alias for `get_sender`."""
|
"""Alias for `get_sender <telethon.tl.custom.sendergetter.SenderGetter.get_sender>`."""
|
||||||
return await self.get_sender()
|
return await self.get_sender()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def input_user(self):
|
def input_user(self):
|
||||||
"""Alias for `input_sender`."""
|
"""Alias for `input_sender <telethon.tl.custom.sendergetter.SenderGetter.input_sender>`."""
|
||||||
return self.input_sender
|
return self.input_sender
|
||||||
|
|
||||||
async def get_input_user(self):
|
async def get_input_user(self):
|
||||||
"""Alias for `get_input_sender`."""
|
"""Alias for `get_input_sender <telethon.tl.custom.sendergetter.SenderGetter.get_input_sender>`."""
|
||||||
return await self.get_input_sender()
|
return await self.get_input_sender()
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def user_id(self):
|
def user_id(self):
|
||||||
"""Alias for `sender_id`."""
|
"""Alias for `sender_id <telethon.tl.custom.sendergetter.SenderGetter.sender_id>`."""
|
||||||
return self.sender_id
|
return self.sender_id
|
||||||
|
|
|
@ -33,11 +33,11 @@ class InlineBuilder:
|
||||||
May be ``True`` to indicate that the game will be sent.
|
May be ``True`` to indicate that the game will be sent.
|
||||||
|
|
||||||
buttons (`list`, `custom.Button <telethon.tl.custom.button.Button>`, :tl:`KeyboardButton`, optional):
|
buttons (`list`, `custom.Button <telethon.tl.custom.button.Button>`, :tl:`KeyboardButton`, optional):
|
||||||
Same as ``buttons`` for `client.send_message
|
Same as ``buttons`` for `client.send_message()
|
||||||
<telethon.client.messages.MessageMethods.send_message>`.
|
<telethon.client.messages.MessageMethods.send_message>`.
|
||||||
|
|
||||||
parse_mode (`str`, optional):
|
parse_mode (`str`, optional):
|
||||||
Same as ``parse_mode`` for `client.send_message
|
Same as ``parse_mode`` for `client.send_message()
|
||||||
<telethon.client.messageparse.MessageParseMethods.parse_mode>`.
|
<telethon.client.messageparse.MessageParseMethods.parse_mode>`.
|
||||||
|
|
||||||
id (`str`, optional):
|
id (`str`, optional):
|
||||||
|
@ -119,7 +119,7 @@ class InlineBuilder:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file (`obj`, optional):
|
file (`obj`, optional):
|
||||||
Same as ``file`` for `client.send_file
|
Same as ``file`` for `client.send_file()
|
||||||
<telethon.client.uploads.UploadMethods.send_file>`.
|
<telethon.client.uploads.UploadMethods.send_file>`.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
|
@ -173,7 +173,7 @@ class InlineBuilder:
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
file (`obj`):
|
file (`obj`):
|
||||||
Same as ``file`` for `client.send_file
|
Same as ``file`` for `client.send_file()
|
||||||
<telethon.client.uploads.UploadMethods.send_file>`.
|
<telethon.client.uploads.UploadMethods.send_file>`.
|
||||||
|
|
||||||
title (`str`, optional):
|
title (`str`, optional):
|
||||||
|
|
|
@ -784,6 +784,22 @@ class Message(ChatGetter, SenderGetter, TLObject, abc.ABC):
|
||||||
behave as if it clicked a button with said data. Note
|
behave as if it clicked a button with said data. Note
|
||||||
that if the message does not have this data, it will
|
that if the message does not have this data, it will
|
||||||
``raise DataInvalidError``.
|
``raise DataInvalidError``.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Click the first button
|
||||||
|
message.click(0)
|
||||||
|
|
||||||
|
# Click some row/column
|
||||||
|
message.click(row, column)
|
||||||
|
|
||||||
|
# Click by text
|
||||||
|
message.click(text='👍')
|
||||||
|
|
||||||
|
# Click by data
|
||||||
|
message.click(data=b'payload')
|
||||||
"""
|
"""
|
||||||
if not self._client:
|
if not self._client:
|
||||||
return
|
return
|
||||||
|
|
|
@ -937,11 +937,12 @@ def _encode_telegram_base64(string):
|
||||||
|
|
||||||
def resolve_bot_file_id(file_id):
|
def resolve_bot_file_id(file_id):
|
||||||
"""
|
"""
|
||||||
Given a Bot API-style `file_id`, returns the media it represents.
|
Given a Bot API-style `file_id <telethon.tl.custom.file.File.id>`,
|
||||||
If the `file_id` is not valid, ``None`` is returned instead.
|
returns the media it represents. If the `file_id <telethon.tl.custom.file.File.id>`
|
||||||
|
is not valid, ``None`` is returned instead.
|
||||||
|
|
||||||
Note that the `file_id` does not have information such as image
|
Note that the `file_id <telethon.tl.custom.file.File.id>` does not have information
|
||||||
dimensions or file size, so these will be zero if present.
|
such as image dimensions or file size, so these will be zero if present.
|
||||||
|
|
||||||
For thumbnails, the photo ID and hash will always be zero.
|
For thumbnails, the photo ID and hash will always be zero.
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue
Block a user