mirror of
https://github.com/LonamiWebs/Telethon.git
synced 2025-08-09 13:29:47 +00:00
Add documentation
This commit is contained in:
117
client/doc/concepts/botapi-vs-mtproto.rst
Normal file
117
client/doc/concepts/botapi-vs-mtproto.rst
Normal file
@@ -0,0 +1,117 @@
|
||||
HTTP Bot API vs MTProto
|
||||
=======================
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
Telethon is more than capable to develop bots for Telegram.
|
||||
If you haven't decided which wrapper library for bots to use yet,
|
||||
using Telethon from the beginning may save you some headaches later.
|
||||
|
||||
|
||||
What is Bot API?
|
||||
----------------
|
||||
|
||||
`Telegram's HTTP Bot API <https://core.telegram.org/bots/api>`_,
|
||||
from now on referred to as simply "Bot API", is Telegram's official way for developers to control their own Telegram bots.
|
||||
Quoting their main page:
|
||||
|
||||
.. epigraph::
|
||||
|
||||
The Bot API is an HTTP-based interface created for developers keen on building bots for Telegram.
|
||||
|
||||
To learn how to create and set up a bot, please consult our
|
||||
`Introduction to Bots <https://core.telegram.org/bots>`_
|
||||
and `Bot FAQ <https://core.telegram.org/bots/faq>`_.
|
||||
|
||||
Bot API is simply an HTTP endpoint offering a custom HTTP API.
|
||||
Underneath, it uses `tdlib <https://core.telegram.org/tdlib>`_ to talk to Telegram's servers.
|
||||
|
||||
You can configure your bot details via `@BotFather <https://t.me/BotFather>`_.
|
||||
This includes name, commands, and auto-completion.
|
||||
|
||||
|
||||
What is MTProto?
|
||||
----------------
|
||||
|
||||
`MTProto <https://core.telegram.org/mtproto>`_ stands for "Mobile Transport Protocol".
|
||||
It is the language that the Telegram servers "speak".
|
||||
You can think of it as an alternative to HTTP.
|
||||
|
||||
Telegram offers multiple APIs.
|
||||
All user accounts must use the API offered via MTProto.
|
||||
We will call this API the "MTProto API".
|
||||
This is the canonical Telegram API.
|
||||
|
||||
The MTProto API is different from Bot API, but bot accounts can use either in the same way.
|
||||
In fact, the Bot API is implemented to use the MTProto API to map the requests and responses.
|
||||
|
||||
Telethon implements the MTProto and offers classes and methods that can be called to send requests.
|
||||
In Telethon, all the methods and types generated from Telegram's API definitions are also known as :term:`Raw API`.
|
||||
This name was chosen because it gives you "raw" access to the MTProto API.
|
||||
Telethon's :class:`Client` and other custom types are implemented using the :term:`Raw API`.
|
||||
|
||||
|
||||
Advantages of MTProto over Bot API
|
||||
----------------------------------
|
||||
|
||||
MTProto clients (like Telethon) connect directly to Telegram's servers via TCP or UDP.
|
||||
There is no HTTP connection, no "polling", and no "web hooks".
|
||||
We can compare the two visually:
|
||||
|
||||
.. graphviz::
|
||||
:caption: Communication between a Client and the Bot API
|
||||
|
||||
digraph botapi {
|
||||
rankdir=LR;
|
||||
"Client" -> "HTTP API";
|
||||
"HTTP API" -> "MTProto API";
|
||||
"MTProto API" -> "Telegram Servers";
|
||||
|
||||
"Telegram Servers" -> "MTProto API" [label="IPC"];
|
||||
"MTProto API" -> "HTTP API" [label="MTProto"];
|
||||
"HTTP API" -> "Client" [label="JSON"];
|
||||
}
|
||||
|
||||
.. graphviz::
|
||||
:caption: Communication between a Client and the MTProto API
|
||||
|
||||
digraph botapi {
|
||||
rankdir=LR;
|
||||
"Client" -> "MTProto API";
|
||||
"MTProto API" -> "Telegram Servers";
|
||||
|
||||
"Telegram Servers" -> "MTProto API" [label="IPC"];
|
||||
"MTProto API" -> "Client" [label="MTProto"];
|
||||
}
|
||||
|
||||
When interacting with the MTProto API directly, we can cut down one intermediary (the HTTP API).
|
||||
This is less theoretical overhead and latency.
|
||||
It also means that, even if the Bot API endpoint is down, talking to the MTProto API could still work.
|
||||
|
||||
The methods offered by the Bot API map to some of the methods in the MTProto API, but not all.
|
||||
The Bot API is its own abstraction, and chooses to expose less details.
|
||||
By talking to the MTProto API directly, you unlock the `full potential <https://github.com/LonamiWebs/Telethon/wiki/MTProto-vs-HTTP-Bot-API>`_.
|
||||
|
||||
The serialization format used by MTProto is more compact than JSON and can still be compressed.
|
||||
|
||||
Another benefit of avoiding the Bot API is the ease to switch to user accounts instead of bots.
|
||||
The MTProto API is the same for users and bots, so by using Telethon, you don't need to learn to use a second library.
|
||||
|
||||
|
||||
Migrating from Bot API to Telethon
|
||||
----------------------------------
|
||||
|
||||
If the above points convinced you to switch to Telethon, the following short guides should help you make the switch!
|
||||
|
||||
It doesn't matter if you wrote your bot with `requests <https://pypi.org/project/requests/>`_
|
||||
and you were making API requests manually, or if you used a wrapper library like
|
||||
`python-telegram-bot <https://python-telegram-bot.readthedocs.io>`_
|
||||
or `pyTelegramBotAPI <https://pytba.readthedocs.io/en/latest/index.html>`.
|
||||
You will surely be pleased with Telethon!
|
||||
|
||||
If you were using an asynchronous library like `aiohttp <https://docs.aiohttp.org/en/stable>`_
|
||||
or a wrapper like `aiogram <https://docs.aiohttp.org/en/stable>`_, the switch will be even easier.
|
||||
|
||||
|
||||
Migrating from TODO
|
||||
^^^^^^^^^^^^^^^^^^^
|
108
client/doc/concepts/chats.rst
Normal file
108
client/doc/concepts/chats.rst
Normal file
@@ -0,0 +1,108 @@
|
||||
Chats
|
||||
=====
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
The term :term:`chat` is extremely overloaded, so it's no surprise many are confused by what it means.
|
||||
This section should hopefully clear that up.
|
||||
|
||||
|
||||
Telethon Chat
|
||||
-------------
|
||||
|
||||
The word :term:`chat` in Telethon is used to refer a place where messages are sent to.
|
||||
Therefore, a Telethon :term:`chat` can be another user, a bot, a group, or a broadcast channel.
|
||||
All of those are places where messages can be sent.
|
||||
|
||||
Of course, chats do more things than contain messages.
|
||||
They often have a name, username, photo, description, and other information.
|
||||
|
||||
When a :term:`chat` appears in a parameter or as a property,
|
||||
it means that it will be either a :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||
|
||||
When a parameter must be "chat-like", it means Telethon will accept anything that can be "converted" to a :term:`chat`.
|
||||
The following types are chat-like:
|
||||
|
||||
* The ``'me'`` literal string. This represents the account that is logged in ("yourself").
|
||||
* An ``'@username'``. The at-sign ``@`` is optional. Note that links are not supported.
|
||||
* An ``'+1 23'`` phone number string. It must be an ``str`` and start with the plus-sign ``+`` character.
|
||||
* An ``123`` integer identifier. It must be an ``int`` and cannot be negative.
|
||||
* An existing :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||
* A :class:`~types.PackedChat`.
|
||||
|
||||
Previous versions of Telethon referred to this term as "entity" or "entities" instead.
|
||||
|
||||
|
||||
Telegram Chat
|
||||
-------------
|
||||
|
||||
The Telegram API is very confusing when it comes to the word "chat".
|
||||
You only need to know about this if you plan to use the :term:`Raw API`.
|
||||
|
||||
In the schema definitions, there are two boxed types, :tl:`User` and :tl:`Chat`.
|
||||
A boxed :tl:`User` can only be the bare :tl:`user`, but the boxed :tl:`Chat` can be either a bare :tl:`chat` or a bare :tl:`channel`.
|
||||
|
||||
A bare :tl:`chat` always refers to small groups.
|
||||
A bare :tl:`channel` can have either the ``broadcast`` or the ``megagroup`` flag set to ``True``.
|
||||
|
||||
A bare :tl:`channel` with the ``broadcast`` flag set to ``True`` is known as a broadcast channel.
|
||||
A bare :tl:`channel` with the ``megagroup`` flag set to ``True`` is known as a supergroup.
|
||||
|
||||
A bare :tl:`chat` with has less features than a bare :tl:`channel` ``megagroup``.
|
||||
Official clients are very good at hiding this difference.
|
||||
They will implicitly convert bare :tl:`chat` to bare :tl:`channel` ``megagroup`` when doing certain operations.
|
||||
Doing things like setting a username is actually a two-step process (migration followed by updating the username).
|
||||
Official clients transparently merge the history of migrated :tl:`channel` with their old :tl:`chat`.
|
||||
|
||||
In Telethon:
|
||||
|
||||
* A :class:`~types.User` always corresponds to :tl:`user`.
|
||||
* A :class:`~types.Group` represents either a :tl:`chat` or a :tl:`channel` ``megagroup``.
|
||||
* A :class:`~types.Channel` represents a :tl:`channel` ``broadcast``.
|
||||
|
||||
Telethon classes aim to map to similar concepts in official applications.
|
||||
|
||||
|
||||
Bot API chat
|
||||
------------
|
||||
|
||||
The Bot API follows a certain convention when it comes to identifiers:
|
||||
|
||||
* User IDs are positive.
|
||||
* Chat IDs are negative.
|
||||
* Channel IDs are prefixed with ``-100``.
|
||||
|
||||
Telethon encourages the use of :class:`~types.PackedChat` instead of naked identifiers.
|
||||
As a reminder, negative identifiers are not supported in Telethon's chat-like parameters.
|
||||
|
||||
|
||||
Encountering chats
|
||||
------------------
|
||||
|
||||
The way you encounter chats in Telethon is no different from official clients.
|
||||
If you:
|
||||
|
||||
* …have joined a group or channel, or have sent private messages to some user, you can :meth:`~Client.get_dialogs`.
|
||||
* …know the user is in your contact list, you can :meth:`~Client.get_contacts`.
|
||||
* …know the user has a common chat with you, you can :meth:`~Client.get_participants` of the chat in common.
|
||||
* …know the username of the user, group, or channel, you can :meth:`~Client.resolve_username`.
|
||||
* …are a bot responding to users, you will be able to access the :attr:`types.Message.sender`.
|
||||
|
||||
Chats access hash
|
||||
-----------------
|
||||
|
||||
Users, supergroups and channels all need an :term:`access hash`.
|
||||
|
||||
In Telethon, the :class:`~types.PackedChat` is the recommended way to deal with the identifier-hash pairs.
|
||||
This compact type can be used anywhere a chat is expected.
|
||||
It's designed to be easy to store and cache in any way your application chooses.
|
||||
|
||||
Bot accounts can get away with an invalid :term:`access hash` for certain operations under certain conditions.
|
||||
The same is true for user accounts, although to a lesser extent.
|
||||
|
||||
When using just the identifier to refer to a chat, Telethon will attempt to retrieve its hash from its in-memory cache.
|
||||
If this fails, an invalid hash will be used. This may or may not make the API call succeed.
|
||||
For this reason, it is recommended that you always use :class:`~types.PackedChat` instead.
|
||||
|
||||
Remember that an :term:`access hash` is account-bound.
|
||||
You cannot obtain an :term:`access hash` in Account-A and use it in Account-B.
|
40
client/doc/concepts/errors.rst
Normal file
40
client/doc/concepts/errors.rst
Normal file
@@ -0,0 +1,40 @@
|
||||
RPC Errors
|
||||
==========
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
:term:`RPC` stands for Remote Procedure Call.
|
||||
By extension, RPC Errors occur when a RPC fails to execute in the server.
|
||||
In Telethon, a :term:`RPC error` corresponds to the :class:`RpcError` class.
|
||||
|
||||
Telethon will only ever raise :class:`RpcError` when the result to a :term:`RPC` is an error.
|
||||
If the error is raised, you know it comes from Telegram.
|
||||
Consequently, when using :term:`Raw API`, if a :class:`RpcError` occurs, it is never a bug in the library.
|
||||
|
||||
:term:`RPC error` consist of an integer :attr:`~RpcError.code` and a string :attr:`~RpcError.name`.
|
||||
The :attr:`RpcError.code` is roughly the same as `HTTP status codes <https://developer.mozilla.org/en-US/docs/Web/HTTP/Status>`_.
|
||||
The :attr:`RpcError.name` is often a string in ``SCREAMING_CASE`` and refers to what went wrong.
|
||||
|
||||
Certain error names also contain an integer value.
|
||||
This value is removed from the :attr:`~RpcError.name` and put into :attr:`RpcError.value`.
|
||||
If Telegram responds with ``FLOOD_WAIT_60``, the name would be ``'FLOOD_WAIT'`` and the value ``60``.
|
||||
|
||||
A very common error is ``FLOOD_WAIT``.
|
||||
It occurs when you have attempted to use a request too many times during a certain window of time:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import asyncio
|
||||
from telethon import RpcError
|
||||
|
||||
try:
|
||||
await client.send_message('me', 'Spam')
|
||||
except RpcError as e:
|
||||
# If we get a flood error, sleep. Else, propagate the error.
|
||||
if e.name == 'FLOOD_WAIT':
|
||||
await asyncio.sleep(e.value)
|
||||
else:
|
||||
raise
|
||||
|
||||
Note that the library can automatically handle and retry on ``FLOOD_WAIT`` for you.
|
||||
Refer to the ``flood_sleep_threshold`` of the :class:`Client` to learn how.
|
66
client/doc/concepts/full-api.rst
Normal file
66
client/doc/concepts/full-api.rst
Normal file
@@ -0,0 +1,66 @@
|
||||
The Full API
|
||||
============
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
The API surface offered by Telethon is not exhaustive.
|
||||
Telegram is constantly adding new features, and both implementing and documenting custom methods would an exhausting, never-ending job.
|
||||
|
||||
Telethon concedes to this fact and implements only commonly-used features to keep a lean API.
|
||||
Access to the entirity of Telegram's API via Telethon's :term:`Raw API` is a necessary evil.
|
||||
|
||||
The ``telethon._tl`` module has a leading underscore to signal that it is private.
|
||||
It is not covered by the semver guarantees of the library, but you may need to use it regardless.
|
||||
If the :class:`Client` doesn't offer a method for what you need, using the :term:`Raw API` is inevitable.
|
||||
|
||||
|
||||
Invoking Raw API methods
|
||||
------------------------
|
||||
|
||||
The :term:`Raw API` can be *invoked* in a very similar way to other client methods:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from telethon import _tl as tl
|
||||
|
||||
was_reset = await client(tl.functions.account.reset_wall_papers())
|
||||
|
||||
Inside ``telethon._tl.functions`` you will find a function for every single :term:`RPC` supported by Telegram.
|
||||
The parameters are keyword-only and do not have defaults.
|
||||
Whatever arguments you pass is exactly what Telegram will receive.
|
||||
Whatever is returned is exactly what Telegram responded with.
|
||||
|
||||
All functions inside ``telethon._tl.functions`` will return the serialized request.
|
||||
When calling a :class:`Client` instance with this request as input, it will be sent to Telegram and wait for a response.
|
||||
|
||||
Multiple requests may be in-flight at the same time, specially when using :mod:`asyncio`.
|
||||
Telethon will attempt to combine these into a single "container" when possible as an optimization.
|
||||
|
||||
|
||||
Exploring the Raw API
|
||||
---------------------
|
||||
|
||||
Everything under ``telethon._tl.types`` implements :func:`repr`.
|
||||
This means you can print any response and get the Python representation of that object.
|
||||
|
||||
All types are proper classes with attributes.
|
||||
You do not need to use a regular expression on the string representation to access the field you want.
|
||||
|
||||
Most :term:`RPC` return an abstract class from ``telethon._tl.abcs``.
|
||||
To check for a concrete type, you can use :func:`isinstance`:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
invite = await client(tl.functions.messages.check_chat_invite(hash='aBcDeF'))
|
||||
if isinstance(invite, tl.types.ChatInviteAlready):
|
||||
print(invite.chat)
|
||||
|
||||
The ``telethon._tl`` module is not documented here because it would result in tens of megabytes.
|
||||
Instead, there are multiple alternatives:
|
||||
|
||||
* Use Telethon's separate site to search in the `Telethon Raw API <https://tl.telethon.dev/>`_.
|
||||
This is the recommended way. It also features auto-generated examples.
|
||||
* Use Python's built-in :func:`help` and :func:`dir` to help you navigate the module.
|
||||
* Use an editor with autocompletion support.
|
||||
* Choose the right layer from `Telegram's official API Layers <https://core.telegram.org/api/layers>`_.
|
||||
Note that the `TL Schema <https://core.telegram.org/schema>`_ might not be up-to-date.
|
42
client/doc/concepts/glossary.rst
Normal file
42
client/doc/concepts/glossary.rst
Normal file
@@ -0,0 +1,42 @@
|
||||
Glossary
|
||||
========
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
.. glossary::
|
||||
:sorted:
|
||||
|
||||
chat
|
||||
A :class:`~types.User`, :class:`~types.Group` or :class:`~types.Channel`.
|
||||
|
||||
.. seealso:: The :doc:`../concepts/chats` concept.
|
||||
|
||||
Raw API
|
||||
Functions and types under ``telethon._tl`` that enable access to all of Telegram's API.
|
||||
|
||||
.. seealso:: The :doc:`../concepts/full-api` concept.
|
||||
|
||||
access hash
|
||||
Account-bound integer tied to a specific resource.
|
||||
Users, channels, photos and documents are all resources with an access hash.
|
||||
The access hash doesn't change, but every account will see a different value for the same resource.
|
||||
|
||||
RPC
|
||||
Remote Procedure Call.
|
||||
Invoked when calling a :class:`Client` with a function from ``telethon._tl.functions``.
|
||||
|
||||
RPC Error
|
||||
Error type returned by Telegram.
|
||||
:class:`RpcError` contains an integer code similar to HTTP status codes and a name.
|
||||
|
||||
.. seealso:: The :doc:`../concepts/errors` concept.
|
||||
|
||||
session
|
||||
Data used to securely connect to Telegram and other state related to the logged-in account.
|
||||
|
||||
.. seealso:: The :doc:`../concepts/sessions` concept.
|
||||
|
||||
MTProto
|
||||
Mobile Transport Protocol used to interact with Telegram's API.
|
||||
|
||||
.. seealso:: The :doc:`../concepts/botapi-vs-mtproto` concept.
|
55
client/doc/concepts/sessions.rst
Normal file
55
client/doc/concepts/sessions.rst
Normal file
@@ -0,0 +1,55 @@
|
||||
Sessions
|
||||
========
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
In Telethon, the word :term:`session` is used to refer to the set of data needed to connect to Telegram.
|
||||
This includes the server address of your home datacenter, as well as the authorization key bound to an account.
|
||||
When you first connect to Telegram, an authorization key is generated to encrypt all communication.
|
||||
After login, Telegram remembers this authorization key as logged-in, so you don't need to login again.
|
||||
|
||||
.. important::
|
||||
|
||||
**Do not leak the session file!**
|
||||
Anyone with that file can login to the account stored in it.
|
||||
If you believe someone else has obtained this file, immediately revoke all active sessions from an official client.
|
||||
|
||||
Some auxiliary information such as the user ID of the logged-in user is also kept.
|
||||
|
||||
The update state, which can change every time an update is received from Telegram, is also stored in the session.
|
||||
Telethon needs this information to catch up on all missed updates while your code was not running.
|
||||
This is why it's important to call :meth:`Client.disconnect`.
|
||||
Doing so flushes all the update state to the session and saves it.
|
||||
|
||||
|
||||
Session files
|
||||
-------------
|
||||
|
||||
Telethon defaults to using SQLite to store the session state.
|
||||
The session state is written to ``.session`` files, so make sure your VCS ignores them!
|
||||
To make sure the ``.session`` file is saved, you should call :meth:`Client.disconnect` before exiting the program.
|
||||
|
||||
The first parameter in the :class:`Client` constructor is the session to use.
|
||||
You can use a `str`, a :class:`pathlib.Path` or a :class:`session.Storage`.
|
||||
The string or path are relative to the Current Working Directory.
|
||||
You can use absolute paths or relative paths to folders elsewhere.
|
||||
The ``.session`` extension is automatically added if the path has no extension.
|
||||
|
||||
|
||||
Session storages
|
||||
----------------
|
||||
|
||||
The :class:`session.Storage` abstract base class defines the required methods to create custom storages.
|
||||
Telethon comes with two built-in storages:
|
||||
|
||||
* :class:`~session.SqliteSession`. This is used by default when a string or path is used.
|
||||
* :class:`~session.MemorySession`. This is used by default when the path is ``None``.
|
||||
You can also use it directly when you have a :class:`~session.Session` instance.
|
||||
It's useful when you don't have file-system access.
|
||||
|
||||
If you would like to store the session state in a different way, you can subclass :class:`session.Storage`.
|
||||
|
||||
Some Python installations do not have the ``sqlite3`` module.
|
||||
In this case, attempting to use the default :class:`~session.SqliteSession` will fail.
|
||||
If this happens, you can try reinstalling Python.
|
||||
If you still don't have the ``sqlite3`` module, you should use a different storage.
|
75
client/doc/concepts/updates.rst
Normal file
75
client/doc/concepts/updates.rst
Normal file
@@ -0,0 +1,75 @@
|
||||
Updates
|
||||
=======
|
||||
|
||||
.. currentmodule:: telethon
|
||||
|
||||
Updates are an important topic in a messaging platform like Telegram.
|
||||
After all, you want to be notified as soon as certain events happen, such as new message arrives.
|
||||
|
||||
Telethon abstracts away Telegram updates with :mod:`~telethon.events`.
|
||||
|
||||
.. important::
|
||||
|
||||
It is strongly advised to configure logging when working with events:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
import logging
|
||||
logging.basicConfig(
|
||||
format='[%(levelname) 5s/%(asctime)s] %(name)s: %(message)s',
|
||||
level=logging.WARNING
|
||||
)
|
||||
|
||||
With the above, you will see all warnings and errors and when they happened.
|
||||
|
||||
|
||||
Filtering events
|
||||
----------------
|
||||
|
||||
There is no way to tell Telegram to only send certain updates.
|
||||
Telethon must be received and process all updates to ensure correct ordering.
|
||||
|
||||
Filters are not magic.
|
||||
They work all the same as ``if`` conditions inside your event handlers.
|
||||
However, they offer a more convenient and consistent way to check for certain conditions.
|
||||
|
||||
All built-in filters can be found in :mod:`telethon.events.filters`.
|
||||
|
||||
When registering an event handler, you can optionally define the filter to use.
|
||||
You can retrieve a handler's filter with :meth:`~Client.get_handler_filter`.
|
||||
You can set (and overwrite) a handler's filter with :meth:`~Client.set_handler_filter`.
|
||||
|
||||
Filters are meant to be fast and never raise exceptions.
|
||||
For this reason, filters cannot be asynchronous.
|
||||
This reduces the chance a filter will do slow IO and potentially fail.
|
||||
|
||||
A filter is simply a callable function that takes an event as input and returns a boolean.
|
||||
If the filter returns ``True``, the handler will be called.
|
||||
Using this knowledge, you can create custom filters too.
|
||||
If you need state, you can use a class with a ``__call__`` method defined:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def only_odd_messages(event):
|
||||
"A filter that only handles messages when their ID is divisible by 2"
|
||||
return event.id % 2 == 0
|
||||
|
||||
client.add_event_handler(handler, events.NewMessage, only_odd_messages)
|
||||
|
||||
# ...
|
||||
|
||||
class OnlyDivisibleMessages:
|
||||
"A filter that only handles messages when their ID is divisible by some amount"
|
||||
def __init__(self, divisible_by):
|
||||
self.divisible_by = divisible_by
|
||||
|
||||
def __call__(self, event):
|
||||
return event.id % self.divisible_by == 0
|
||||
|
||||
client.add_event_handler(handler, events.NewMessage, OnlyDivisibleMessages(7))
|
||||
|
||||
Custom filters should accept any :class:`~events.Event`.
|
||||
You can use :func:`isinstance` if your filter can only deal with certain types of events.
|
||||
|
||||
If you need to perform asynchronous operations, you can't use a filter.
|
||||
Instead, manually check for those conditions inside your handler.
|
Reference in New Issue
Block a user