Merge branch 'develop' into asyncio

# Conflicts:
#	pyrogram/client/client.py
#	pyrogram/client/methods/chats/get_chat_members.py
#	pyrogram/client/methods/chats/get_dialogs.py
#	pyrogram/client/methods/messages/send_animation.py
#	pyrogram/client/methods/messages/send_venue.py
This commit is contained in:
Dan 2018-08-22 10:30:25 +02:00
commit 3f7b0b25af
143 changed files with 1556 additions and 745 deletions

View File

@ -494,14 +494,14 @@ def start():
f.write("\n 0xb0700015: \"pyrogram.client.types.ChatPhoto\",")
f.write("\n 0xb0700016: \"pyrogram.client.types.ChatMember\",")
f.write("\n 0xb0700017: \"pyrogram.client.types.Sticker\",")
f.write("\n 0xb0700018: \"pyrogram.client.types.reply_markup.ForceReply\",")
f.write("\n 0xb0700019: \"pyrogram.client.types.reply_markup.InlineKeyboardButton\",")
f.write("\n 0xb0700020: \"pyrogram.client.types.reply_markup.InlineKeyboardMarkup\",")
f.write("\n 0xb0700021: \"pyrogram.client.types.reply_markup.KeyboardButton\",")
f.write("\n 0xb0700022: \"pyrogram.client.types.reply_markup.ReplyKeyboardMarkup\",")
f.write("\n 0xb0700023: \"pyrogram.client.types.reply_markup.ReplyKeyboardRemove\",")
f.write("\n 0xb0700018: \"pyrogram.client.types.bots.ForceReply\",")
f.write("\n 0xb0700019: \"pyrogram.client.types.bots.InlineKeyboardButton\",")
f.write("\n 0xb0700020: \"pyrogram.client.types.bots.InlineKeyboardMarkup\",")
f.write("\n 0xb0700021: \"pyrogram.client.types.bots.KeyboardButton\",")
f.write("\n 0xb0700022: \"pyrogram.client.types.bots.ReplyKeyboardMarkup\",")
f.write("\n 0xb0700023: \"pyrogram.client.types.bots.ReplyKeyboardRemove\",")
f.write("\n 0xb0700024: \"pyrogram.client.types.CallbackQuery\",")
f.write("\n 0xb0700025: \"pyrogram.client.types.GIF\",")
f.write("\n 0xb0700025: \"pyrogram.client.types.Animation\",")
f.write("\n 0xb0700026: \"pyrogram.client.types.Messages\",")
f.write("\n 0xb0700027: \"pyrogram.client.types.Photo\",")
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")

View File

@ -65,4 +65,5 @@ PEER_FLOOD The method can't be used because your account is limited
MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
USER_NOT_PARTICIPANT The user is not a member of this chat
1 id message
65 MEDIA_CAPTION_TOO_LONG The media caption is longer than 200 characters
66 USER_NOT_MUTUAL_CONTACT The user is not a mutual contact
67 USER_CHANNELS_TOO_MUCH The user is already in too many channels or supergroups
68 API_ID_PUBLISHED_FLOOD You are using an API key that is limited on the server side
69 USER_NOT_PARTICIPANT The user is not a member of this chat

View File

@ -84,6 +84,7 @@ To get started, press the Next button.
:caption: Resources
resources/UpdateHandling
resources/UsingFilters
resources/AutoAuthorization
resources/CustomizeSessions
resources/TgCrypto

View File

@ -1,76 +1,133 @@
Client
======
.. currentmodule:::: pyrogram.Client
.. currentmodule:: pyrogram.Client
.. autoclass:: pyrogram.Client
Utilities
---------
.. autosummary::
:nosignatures:
start
stop
idle
run
add_handler
remove_handler
send
resolve_peer
download_media
Decorators
----------
.. autosummary::
:nosignatures:
on_message
on_callback_query
on_deleted_messages
on_disconnect
on_raw_update
Messages
--------
.. autosummary::
:nosignatures:
send_message
forward_messages
send_photo
send_audio
send_document
send_sticker
send_video
send_animation
send_voice
send_video_note
send_media_group
send_location
send_venue
send_contact
send_chat_action
edit_message_text
edit_message_caption
edit_message_reply_markup
delete_messages
get_messages
get_history
get_dialogs
Chats
-----
.. autosummary::
:nosignatures:
join_chat
leave_chat
kick_chat_member
unban_chat_member
restrict_chat_member
promote_chat_member
export_chat_invite_link
set_chat_photo
delete_chat_photo
set_chat_title
set_chat_description
pin_chat_message
unpin_chat_message
get_chat
get_chat_member
get_chat_members
Users
-----
.. autosummary::
:nosignatures:
get_me
get_users
get_user_profile_photos
delete_profile_photos
Contacts
--------
.. autosummary::
:nosignatures:
add_contacts
get_contacts
delete_contacts
Password
--------
.. autosummary::
:nosignatures:
enable_cloud_password
change_cloud_password
remove_cloud_password
Bots
----
.. autosummary::
:nosignatures:
get_inline_bot_results
send_inline_bot_result
answer_callback_query
request_callback_answer
.. autoclass:: pyrogram.Client
:inherited-members:
:members:
.. _available-methods:
**Available methods**
.. autosummary::
:nosignatures:
start
stop
idle
run
on_message
on_callback_query
on_raw_update
add_handler
remove_handler
send
resolve_peer
get_me
send_message
forward_messages
send_photo
send_audio
send_document
send_sticker
send_video
send_voice
send_video_note
send_media_group
send_location
send_venue
send_contact
send_chat_action
download_media
get_user_profile_photos
delete_profile_photos
edit_message_text
edit_message_caption
edit_message_reply_markup
delete_messages
join_chat
leave_chat
export_chat_invite_link
enable_cloud_password
change_cloud_password
remove_cloud_password
kick_chat_member
unban_chat_member
restrict_chat_member
promote_chat_member
add_contacts
get_contacts
delete_contacts
get_inline_bot_results
send_inline_bot_result
answer_callback_query
request_callback_answer
get_users
get_chat
get_messages
get_history
set_chat_photo
delete_chat_photo
set_chat_title
set_chat_description
pin_chat_message
unpin_chat_message

View File

@ -1,5 +1,3 @@
:tocdepth: 1
Error
=====

View File

@ -0,0 +1,29 @@
Handlers
========
.. currentmodule:: pyrogram
.. autosummary::
:nosignatures:
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
DisconnectHandler
RawUpdateHandler
.. autoclass:: MessageHandler
:members:
.. autoclass:: DeletedMessagesHandler
:members:
.. autoclass:: CallbackQueryHandler
:members:
.. autoclass:: DisconnectHandler
:members:
.. autoclass:: RawUpdateHandler
:members:

View File

@ -0,0 +1,176 @@
Types
=====
.. currentmodule:: pyrogram
Users & Chats
-------------
.. autosummary::
:nosignatures:
User
Chat
ChatPhoto
ChatMember
ChatMembers
Dialog
Dialogs
Messages & Media
----------------
.. autosummary::
:nosignatures:
Message
Messages
MessageEntity
Photo
PhotoSize
UserProfilePhotos
Audio
Document
Animation
Video
Voice
VideoNote
Contact
Location
Venue
Sticker
Bots
----
.. autosummary::
:nosignatures:
ReplyKeyboardMarkup
KeyboardButton
ReplyKeyboardRemove
InlineKeyboardMarkup
InlineKeyboardButton
ForceReply
CallbackQuery
Input Media
-----------
.. autosummary::
:nosignatures:
InputMediaPhoto
InputMediaVideo
InputPhoneContact
.. User & Chats
------------
.. autoclass:: User
:members:
.. autoclass:: Chat
:members:
.. autoclass:: ChatPhoto
:members:
.. autoclass:: ChatMember
:members:
.. autoclass:: ChatMembers
:members:
.. autoclass:: Dialog
:members:
.. autoclass:: Dialogs
:members:
.. Messages & Media
----------------
.. autoclass:: Message
:members:
.. autoclass:: Messages
:members:
.. autoclass:: MessageEntity
:members:
.. autoclass:: Photo
:members:
.. autoclass:: PhotoSize
:members:
.. autoclass:: UserProfilePhotos
:members:
.. autoclass:: Audio
:members:
.. autoclass:: Document
:members:
.. autoclass:: Animation
:members:
.. autoclass:: Video
:members:
.. autoclass:: Voice
:members:
.. autoclass:: VideoNote
:members:
.. autoclass:: Contact
:members:
.. autoclass:: Location
:members:
.. autoclass:: Venue
:members:
.. autoclass:: Sticker
:members:
.. Bots
----
.. autoclass:: ReplyKeyboardMarkup
:members:
.. autoclass:: KeyboardButton
:members:
.. autoclass:: ReplyKeyboardRemove
:members:
.. autoclass:: InlineKeyboardMarkup
:members:
.. autoclass:: InlineKeyboardButton
:members:
.. autoclass:: ForceReply
:members:
.. autoclass:: CallbackQuery
:members:
.. Input Media
-----------
.. autoclass:: InputMediaPhoto
:members:
.. autoclass:: InputMediaVideo
:members:
.. autoclass:: InputPhoneContact
:members:

View File

@ -1,6 +0,0 @@
CallbackQueryHandler
====================
.. autoclass:: pyrogram.CallbackQueryHandler
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
DeletedMessagesHandler
======================
.. autoclass:: pyrogram.DeletedMessagesHandler
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
DisconnectHandler
=================
.. autoclass:: pyrogram.DisconnectHandler
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
MessageHandler
==============
.. autoclass:: pyrogram.MessageHandler
:members:
:undoc-members:

View File

@ -1,6 +0,0 @@
RawUpdateHandler
================
.. autoclass:: pyrogram.RawUpdateHandler
:members:
:undoc-members:

View File

@ -1,11 +0,0 @@
:tocdepth: 1
Handlers
========
.. toctree::
MessageHandler
DeletedMessagesHandler
CallbackQueryHandler
DisconnectHandler
RawUpdateHandler

View File

@ -7,9 +7,11 @@ In this section you can find a detailed description of the Pyrogram package and
after the well established `Telegram Bot API`_ methods, thus offering a familiar look to Bot developers.
.. toctree::
:maxdepth: 1
Client
types/index
handlers/index
Types
Handlers
Filters
ChatAction
ParseMode

View File

@ -1,5 +0,0 @@
Audio
=====
.. autoclass:: pyrogram.Audio
:members:

View File

@ -1,5 +0,0 @@
CallbackQuery
=============
.. autoclass:: pyrogram.CallbackQuery
:members:

View File

@ -1,5 +0,0 @@
Chat
====
.. autoclass:: pyrogram.Chat
:members:

View File

@ -1,5 +0,0 @@
ChatMember
==========
.. autoclass:: pyrogram.ChatMember
:members:

View File

@ -1,5 +0,0 @@
ChatPhoto
=========
.. autoclass:: pyrogram.ChatPhoto
:members:

View File

@ -1,5 +0,0 @@
Contact
=======
.. autoclass:: pyrogram.Contact
:members:

View File

@ -1,5 +0,0 @@
Document
========
.. autoclass:: pyrogram.Document
:members:

View File

@ -1,5 +0,0 @@
GIF
===
.. autoclass:: pyrogram.GIF
:members:

View File

@ -1,5 +0,0 @@
InputMediaPhoto
===============
.. autoclass:: pyrogram.InputMediaPhoto
:members:

View File

@ -1,5 +0,0 @@
InputMediaVideo
===============
.. autoclass:: pyrogram.InputMediaVideo
:members:

View File

@ -1,5 +0,0 @@
InputPhoneContact
=================
.. autoclass:: pyrogram.InputPhoneContact
:members:

View File

@ -1,5 +0,0 @@
Location
========
.. autoclass:: pyrogram.Location
:members:

View File

@ -1,5 +0,0 @@
Message
=======
.. autoclass:: pyrogram.Message
:members:

View File

@ -1,5 +0,0 @@
MessageEntity
=============
.. autoclass:: pyrogram.MessageEntity
:members:

View File

@ -1,5 +0,0 @@
Messages
========
.. autoclass:: pyrogram.Messages
:members:

View File

@ -1,5 +0,0 @@
Photo
=====
.. autoclass:: pyrogram.Photo
:members:

View File

@ -1,5 +0,0 @@
PhotoSize
=========
.. autoclass:: pyrogram.PhotoSize
:members:

View File

@ -1,5 +0,0 @@
Sticker
=======
.. autoclass:: pyrogram.Sticker
:members:

View File

@ -1,5 +0,0 @@
Update
======
.. autoclass:: pyrogram.Update
:members:

View File

@ -1,5 +0,0 @@
User
====
.. autoclass:: pyrogram.User
:members:

View File

@ -1,5 +0,0 @@
UserProfilePhotos
=================
.. autoclass:: pyrogram.UserProfilePhotos
:members:

View File

@ -1,5 +0,0 @@
Venue
=====
.. autoclass:: pyrogram.Venue
:members:

View File

@ -1,5 +0,0 @@
Video
=====
.. autoclass:: pyrogram.Video
:members:

View File

@ -1,5 +0,0 @@
VideoNote
=========
.. autoclass:: pyrogram.VideoNote
:members:

View File

@ -1,5 +0,0 @@
Voice
=====
.. autoclass:: pyrogram.Voice
:members:

View File

@ -1,36 +0,0 @@
:tocdepth: 1
Types
=====
.. toctree::
User
Chat
Message
MessageEntity
Messages
Photo
PhotoSize
Audio
Document
GIF
Video
Voice
VideoNote
Contact
Location
Venue
UserProfilePhotos
ChatPhoto
ChatMember
InputMediaPhoto
InputMediaVideo
InputPhoneContact
Sticker
reply_markup/ForceReply
reply_markup/InlineKeyboardButton
reply_markup/InlineKeyboardMarkup
reply_markup/KeyboardButton
reply_markup/ReplyKeyboardMarkup
reply_markup/ReplyKeyboardRemove
CallbackQuery

View File

@ -1,5 +0,0 @@
ForceReply
==========
.. autoclass:: pyrogram.ForceReply
:members:

View File

@ -1,5 +0,0 @@
InlineKeyboardButton
====================
.. autoclass:: pyrogram.InlineKeyboardButton
:members:

View File

@ -1,5 +0,0 @@
InlineKeyboardMarkup
====================
.. autoclass:: pyrogram.InlineKeyboardMarkup
:members:

View File

@ -1,5 +0,0 @@
KeyboardButton
==============
.. autoclass:: pyrogram.KeyboardButton
:members:

View File

@ -1,5 +0,0 @@
ReplyKeyboardMarkup
===================
.. autoclass:: pyrogram.ReplyKeyboardMarkup
:members:

View File

@ -1,5 +0,0 @@
ReplyKeyboardRemove
===================
.. autoclass:: pyrogram.ReplyKeyboardRemove
:members:

View File

@ -1,8 +1,11 @@
Text Formatting
===============
Pyrogram, just like `Telegram Bot API`_, supports basic Markdown and HTML formatting styles for text messages and
media captions; Markdown uses the same syntax as Telegram Desktop's and is enabled by default.
Pyrogram, just like the `Telegram Bot API`_, natively supports basic Markdown and HTML formatting styles for text
messages and media captions.
Markdown style uses the same syntax as Telegram Desktop's and is enabled by default.
Beside bold, italic, and pre-formatted code, **Pyrogram does also support inline URLs and inline mentions of users**.
Markdown Style
@ -11,7 +14,7 @@ Markdown Style
To use this mode, pass :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or "markdown" in the *parse_mode* field when using
:obj:`send_message() <pyrogram.Client.send_message>`. Use the following syntax in your message:
.. code-block:: txt
.. code-block:: text
**bold text**
@ -34,7 +37,7 @@ HTML Style
To use this mode, pass :obj:`HTML <pyrogram.ParseMode.HTML>` or "html" in the *parse_mode* field when using
:obj:`send_message() <pyrogram.Client.send_message>`. The following tags are currently supported:
.. code-block:: txt
.. code-block:: text
<b>bold</b>, <strong>bold</strong>
@ -46,9 +49,7 @@ To use this mode, pass :obj:`HTML <pyrogram.ParseMode.HTML>` or "html" in the *p
<code>inline fixed-width code</code>
<pre>pre-formatted fixed-width
code block
</pre>
<pre>pre-formatted fixed-width code block</pre>
.. note:: Mentions are only guaranteed to work if you have already met the user (in groups or private chats).

View File

@ -2,188 +2,58 @@ Update Handling
===============
Updates are events that happen in your Telegram account (incoming messages, new channel posts, new members join, ...)
and are handled by registering one or more callback functions with an Handler. There are multiple Handlers to choose
from, one for each kind of update:
and can be handled by registering one or more callback functions in your app by using an `Handler <../pyrogram/Handlers.html>`_.
- `MessageHandler <../pyrogram/handlers/MessageHandler.html>`_
- `DeletedMessagesHandler <../pyrogram/handlers/DeletedMessagesHandler.html>`_
- `CallbackQueryHandler <../pyrogram/handlers/CallbackQueryHandler.html>`_
- `RawUpdateHandler <../pyrogram/handlers/RawUpdateHandler.html>`_
- `DisconnectHandler <../pyrogram/handlers/DisconnectHandler.html>`_
To put it simply, whenever an update is received from Telegram it will be dispatched and your previously defined callback
function(s) will be called back with the update itself as argument.
Registering an Handler
----------------------
We shall examine the :obj:`MessageHandler <pyrogram.MessageHandler>`, which will be in charge for handling
:obj:`Message <pyrogram.Message>` objects.
- The easiest and nicest way to register a MessageHandler is by decorating your function with the
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
of a message as soon as it arrives.
.. code-block:: python
from pyrogram import Client
app = Client("my_account")
To explain how `Handlers <../pyrogram/Handlers.html>`_ work let's have a look at the most used one, the
:obj:`MessageHandler <pyrogram.MessageHandler>`, which will be in charge for handling :obj:`Message <pyrogram.Message>`
updates coming from all around your chats. Every other handler shares the same setup logic; you should not have troubles
settings them up once you learn from this section.
@app.on_message()
def my_handler(client, message):
print(message)
app.run()
- If you prefer not to use decorators, there is an alternative way for registering Handlers.
This is useful, for example, when you want to keep your callback functions in separate files.
.. code-block:: python
from pyrogram import Client, MessageHandler
def my_handler(client, message):
print(message)
app = Client("my_account")
app.add_handler(MessageHandler(my_handler))
app.run()
Using Filters
-------------
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
:class:`Filters <pyrogram.Filters>`.
- This example will show you how to **only** handle messages containing an
:obj:`Audio <pyrogram.Audio>` object and filter out any other message:
.. code-block:: python
from pyrogram import Filters
@app.on_message(Filters.audio)
def my_handler(client, message):
print(message)
- or, without decorators:
.. code-block:: python
from pyrogram import Filters, MessageHandler
def my_handler(client, message):
print(message)
app.add_handler(MessageHandler(my_handler, Filters.audio))
Combining Filters
-----------------
Filters can also be used in a more advanced way by combining more filters together using bitwise operators:
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
Here are some examples:
- Message is a **text** message **and** is **not edited**.
.. code-block:: python
@app.on_message(Filters.text & ~Filters.edited)
def my_handler(client, message):
print(message)
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
.. code-block:: python
@app.on_message(Filters.sticker & (Filters.channel | Filters.private))
def my_handler(client, message):
print(message)
Advanced Filters
Using Decorators
----------------
Some filters, like :obj:`command() <pyrogram.Filters.command>` or :obj:`regex() <pyrogram.Filters.regex>`
can also accept arguments:
- Message is either a */start* or */help* **command**.
.. code-block:: python
@app.on_message(Filters.command(["start", "help"]))
def my_handler(client, message):
print(message)
- Message is a **text** message matching the given **regex** pattern.
.. code-block:: python
@app.on_message(Filters.regex("pyrogram"))
def my_handler(client, message):
print(message)
More handlers using different filters can also live together.
The easiest and nicest way to register a MessageHandler is by decorating your function with the
:meth:`on_message() <pyrogram.Client.on_message>` decorator. Here's a full example that prints out the content
of a message as soon as it arrives.
.. code-block:: python
@app.on_message(Filters.command("start"))
def start_command(client, message):
print("This is the /start command")
from pyrogram import Client
app = Client("my_account")
@app.on_message(Filters.command("help"))
def help_command(client, message):
print("This is the /help command")
@app.on_message()
def my_handler(client, message):
print(message)
@app.on_message(Filters.chat("PyrogramChat"))
def from_pyrogramchat(client, message):
print("New message in @PyrogramChat")
app.run()
Handler Groups
--------------
Using add_handler()
-------------------
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
In order to process the same message more than once, you can register your handler in a different group.
Groups are identified by a number (number 0 being the default) and are sorted. This means that a lower group number has
a higher priority.
For example, in:
If you prefer not to use decorators for any reason, there is an alternative way for registering Handlers.
This is useful, for example, when you want to keep your callback functions in separate files.
.. code-block:: python
@app.on_message(Filters.text | Filters.sticker)
def text_or_sticker(client, message):
print("Text or Sticker")
from pyrogram import Client, MessageHandler
@app.on_message(Filters.text)
def just_text(client, message):
print("Just Text")
def my_handler(client, message):
print(message)
``just_text`` is never executed. To enable it, simply register the function using a different group:
.. code-block:: python
app = Client("my_account")
@app.on_message(Filters.text, group=1)
def just_text(client, message):
print("Just Text")
app.add_handler(MessageHandler(my_handler))
or, if you want ``just_text`` to be fired *before* ``text_or_sticker``:
.. code-block:: python
@app.on_message(Filters.text, group=-1)
def just_text(client, message):
print("Just Text")
app.run()

View File

@ -0,0 +1,228 @@
Using Filters
=============
For a finer grained control over what kind of messages will be allowed or not in your callback functions, you can use
:class:`Filters <pyrogram.Filters>`.
.. note::
This section makes use of Handlers to handle updates. Learn more at `Update Handling <UpdateHandling.html>`_.
- This example will show you how to **only** handle messages containing an :obj:`Audio <pyrogram.Audio>` object and
ignore any other message:
.. code-block:: python
from pyrogram import Filters
@app.on_message(Filters.audio)
def my_handler(client, message):
print(message)
- or, without decorators:
.. code-block:: python
from pyrogram import Filters, MessageHandler
def my_handler(client, message):
print(message)
app.add_handler(MessageHandler(my_handler, Filters.audio))
Combining Filters
-----------------
Filters can also be used in a more advanced way by inverting and combining more filters together using bitwise
operators:
- Use ``~`` to invert a filter (behaves like the ``not`` operator).
- Use ``&`` and ``|`` to merge two filters (behave like ``and``, ``or`` operators respectively).
Here are some examples:
- Message is a **text** message **and** is **not edited**.
.. code-block:: python
@app.on_message(Filters.text & ~Filters.edited)
def my_handler(client, message):
print(message)
- Message is a **sticker** **and** is coming from a **channel or** a **private** chat.
.. code-block:: python
@app.on_message(Filters.sticker & (Filters.channel | Filters.private))
def my_handler(client, message):
print(message)
Advanced Filters
----------------
Some filters, like :meth:`command() <pyrogram.Filters.command>` or :meth:`regex() <pyrogram.Filters.regex>`
can also accept arguments:
- Message is either a */start* or */help* **command**.
.. code-block:: python
@app.on_message(Filters.command(["start", "help"]))
def my_handler(client, message):
print(message)
- Message is a **text** message matching the given **regex** pattern.
.. code-block:: python
@app.on_message(Filters.regex("pyrogram"))
def my_handler(client, message):
print(message)
More handlers using different filters can also live together.
.. code-block:: python
@app.on_message(Filters.command("start"))
def start_command(client, message):
print("This is the /start command")
@app.on_message(Filters.command("help"))
def help_command(client, message):
print("This is the /help command")
@app.on_message(Filters.chat("PyrogramChat"))
def from_pyrogramchat(client, message):
print("New message in @PyrogramChat")
Handler Groups
--------------
If you register handlers with overlapping filters, only the first one is executed and any other handler will be ignored.
In order to process the same message more than once, you can register your handler in a different group.
Groups are identified by a number (number 0 being the default) and are sorted. This means that a lower group number has
a higher priority.
For example, in:
.. code-block:: python
@app.on_message(Filters.text | Filters.sticker)
def text_or_sticker(client, message):
print("Text or Sticker")
@app.on_message(Filters.text)
def just_text(client, message):
print("Just Text")
``just_text`` is never executed because ``text_or_sticker`` already handles texts. To enable it, simply register the
function using a different group:
.. code-block:: python
@app.on_message(Filters.text, group=1)
def just_text(client, message):
print("Just Text")
or, if you want ``just_text`` to be fired *before* ``text_or_sticker`` (note ``-1``, which is less than ``0``):
.. code-block:: python
@app.on_message(Filters.text, group=-1)
def just_text(client, message):
print("Just Text")
Custom Filters
--------------
Pyrogram already provides lots of built-in :class:`Filters <pyrogram.Filters>` to work with, but in case you can't find
a specific one for your needs or want to build a custom filter by yourself (to be used in a different handler, for
example) you can use :meth:`Filters.create() <pyrogram.Filters.create>`.
.. note::
At the moment, the built-in filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`
only.
An example to demonstrate how custom filters work is to show how to create and use one for the
:obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>`. Note that callback queries updates are only received by Bots;
create and `authorize your bot <../start/Setup.html#bot-authorization>`_, then send a message with an inline keyboard to
yourself. This allows you to test your filter by pressing the inline button:
.. code-block:: python
from pyrogram import InlineKeyboardMarkup, InlineKeyboardButton
app.send_message(
"username", # Change this to your username or id
"Pyrogram's custom filter test",
reply_markup=InlineKeyboardMarkup(
[[InlineKeyboardButton("Press me", "pyrogram")]]
)
)
Basic Filters
^^^^^^^^^^^^^
For this basic filter we will be using only the first two parameters of :meth:`Filters.create() <pyrogram.Filters.create>`.
The code below creates a simple filter for hardcoded callback data. This filter will only allow callback queries
containing "pyrogram" as data:
.. code-block:: python
hardcoded_data = Filters.create(
name="HardcodedData",
func=lambda filter, callback_query: callback_query.data == "pyrogram"
)
The ``lambda`` operator in python is used to create small anonymous functions and is perfect for this example, the same
could be achieved with a normal function, but we don't really need it as it makes sense only inside the filter itself:
.. code-block:: python
def func(filter, callback_query):
return callback_query.data == "pyrogram"
hardcoded_data = Filters.create(
name="HardcodedData",
func=func
)
The filter usage remains the same:
.. code-block:: python
@app.on_callback_query(hardcoded_data)
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")
Filters with Arguments
^^^^^^^^^^^^^^^^^^^^^^
A much cooler filter would be one that accepts "pyrogram" or any other data as argument at usage time.
A dynamic filter like this will make use of the third parameter of :meth:`Filters.create() <pyrogram.Filters.create>`.
This is how a dynamic custom filter looks like:
.. code-block:: python
def dynamic_data(data):
return Filters.create(
name="DynamicData",
func=lambda filter, callback_query: filter.data == callback_query.data,
data=data # "data" kwarg is accessed with "filter.data"
)
And its usage:
.. code-block:: python
@app.on_callback_query(dynamic_data("pyrogram"))
def pyrogram_data(client, callback_query):
client.answer_callback_query(callback_query.id, "it works!")

View File

@ -7,7 +7,8 @@ We recommend using the latest version of Python 3 and pip.
Get Python 3 from https://www.python.org/downloads/ or with your package manager and pip
by following the instructions at https://pip.pypa.io/en/latest/installing/.
Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
.. note::
Pyrogram supports Python 3 only, starting from version 3.4 and PyPy.
Install Pyrogram
----------------

View File

@ -8,22 +8,29 @@ with Pyrogram.
API Keys
--------
The very first step requires you to obtain a valid Telegram API key.
The very first step requires you to obtain a valid Telegram API key (API id/hash pair).
If you already have one you can skip this step, otherwise:
#. Visit https://my.telegram.org/apps and log in with your Telegram Account.
#. Fill out the form to register a new Telegram application.
#. Done. The Telegram API key consists of two parts: the **App api_id** and the **App api_hash**.
#. Done. The API key consists of two parts: **App api_id** and **App api_hash**.
.. important:: This key should be kept secret.
.. important::
This API key is personal and should be kept secret.
Configuration
-------------
There are two ways to configure a Pyrogram application project, and you can choose the one that fits better for you:
The API key obtained in the `previous step <#api-keys>`_ defines a token for your application allowing you to access
the Telegram database using the MTProto API — **it is therefore required for all authorizations of both Users and Bots**.
Having it handy, it's time to configure your Pyrogram project. There are two ways to do so, and you can choose what
fits better for you:
- Create a new ``config.ini`` file at the root of your working directory, copy-paste the following and replace the
**api_id** and **api_hash** values with `your own <#api-keys>`_. This is the preferred method because allows you
**api_id** and **api_hash** values with your own. This is the preferred method because allows you
to keep your credentials out of your code without having to deal with how to load them:
.. code-block:: ini
@ -45,7 +52,8 @@ There are two ways to configure a Pyrogram application project, and you can choo
api_hash="0123456789abcdef0123456789abcdef"
)
.. note:: The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
.. note::
The examples below assume you have created a ``config.ini`` file, thus they won't show the *api_id*
and *api_hash* parameters usage.
User Authorization
@ -76,16 +84,17 @@ After successfully authorizing yourself, a new file called ``my_account.session`
Pyrogram executing API calls with your identity. This file will be loaded again when you restart your app,
and as long as you keep the session alive, Pyrogram won't ask you again to enter your phone number.
.. important:: Your ``*.session`` file(s) must be kept secret.
.. important:: Your ``*.session`` files are personal and must be kept secret.
Bot Authorization
-----------------
Being written entirely from the ground up, Pyrogram is also able to authorize Bots.
Bots are a special kind of users which also make use of MTProto, the underlying Telegram protocol.
This means that you can use Pyrogram to execute API calls with a Bot identity.
Bots are a special kind of users and are authorized via their tokens (instead of phone numbers), which are created by
BotFather_. Bot tokens replace the Users' phone numbers only — you still need to
`configure a Telegram API key <#configuration>`_ with Pyrogram, even when using Bots.
Instead of phone numbers, Bots are authorized via their tokens which are created by BotFather_:
The authorization process is automatically managed. All you need to do is pass the bot token as ``session_name``.
The session file will be named after the Bot user_id, which is ``123456.session`` for the example below.
.. code-block:: python
@ -94,9 +103,6 @@ Instead of phone numbers, Bots are authorized via their tokens which are created
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
app.run()
That's all, no further action is needed. The session file will be named after the Bot user_id, which is
``123456.session`` for the example above.
.. _installed Pyrogram: Installation.html
.. _`Country Code`: https://en.wikipedia.org/wiki/List_of_country_calling_codes
.. _BotFather: https://t.me/botfather

View File

@ -108,9 +108,9 @@ Examples (more on `GitHub <https://github.com/pyrogram/pyrogram/tree/develop/exa
app.stop()
.. _methods: ../pyrogram/Client.html#available-methods
.. _plenty of them: ../pyrogram/Client.html#available-methods
.. _types: ../pyrogram/types/index.html
.. _methods: ../pyrogram/Client.html#messages
.. _plenty of them: ../pyrogram/Client.html#messages
.. _types: ../pyrogram/Types.html
.. _Raw Functions: Usage.html#using-raw-functions
.. _Community: https://t.me/PyrogramChat
.. _project set up: Setup.html

View File

@ -36,11 +36,10 @@ __version__ = "0.8.0dev1"
from .api.errors import Error
from .client.types import (
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
InputMediaVideo, InputPhoneContact, Location, Message, MessageEntity,
Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserProfilePhotos,
Venue, GIF, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup,
ReplyKeyboardRemove
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User,
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove
)
from .client import (
Client, ChatAction, ParseMode, Emoji,

View File

@ -1009,21 +1009,19 @@ class Client(Methods, BaseClient):
await self.get_initial_dialogs_chunk()
async def resolve_peer(self, peer_id: int or str):
"""Use this method to get the *InputPeer* of a known *peer_id*.
"""Use this method to get the InputPeer of a known peer_id.
It is intended to be used when working with Raw Functions (i.e: a Telegram API method you wish to use which is
not available yet in the Client class as an easy-to-use method).
This is a utility method intended to be used only when working with Raw Functions (i.e: a Telegram API method
you wish to use which is not available yet in the Client class as an easy-to-use method), whenever an InputPeer
type is required.
Args:
peer_id (``int`` | ``str`` | ``Peer``):
The Peer ID you want to extract the InputPeer from. Can be one of these types: ``int`` (direct ID),
``str`` (@username), :obj:`PeerUser <pyrogram.api.types.PeerUser>`,
:obj:`PeerChat <pyrogram.api.types.PeerChat>`, :obj:`PeerChannel <pyrogram.api.types.PeerChannel>`
peer_id (``int`` | ``str``):
The peer id you want to extract the InputPeer from.
Can be a direct id (int), a username (str) or a phone number (str).
Returns:
:obj:`InputPeerUser <pyrogram.api.types.InputPeerUser>` or
:obj:`InputPeerChat <pyrogram.api.types.InputPeerChat>` or
:obj:`InputPeerChannel <pyrogram.api.types.InputPeerChannel>` depending on the *peer_id*.
On success, the resolved peer id is returned in form of an InputPeer object.
Raises:
:class:`Error <pyrogram.Error>`
@ -1032,38 +1030,21 @@ class Client(Methods, BaseClient):
if peer_id in ("self", "me"):
return types.InputPeerSelf()
match = self.INVITE_LINK_RE.match(peer_id)
try:
decoded = base64.b64decode(match.group(1) + "=" * (-len(match.group(1)) % 4), "-_")
return await self.resolve_peer(struct.unpack(">2iq", decoded)[1])
except (AttributeError, binascii.Error, struct.error):
pass
peer_id = re.sub(r"[@+\s]", "", peer_id.lower())
try:
int(peer_id)
except ValueError:
try:
return self.peers_by_username[peer_id]
except KeyError:
if peer_id not in self.peers_by_username:
await self.send(functions.contacts.ResolveUsername(peer_id))
return self.peers_by_username[peer_id]
return self.peers_by_username[peer_id]
else:
try:
return self.peers_by_phone[peer_id]
except KeyError:
raise PeerIdInvalid
if type(peer_id) is not int:
if isinstance(peer_id, types.PeerUser):
peer_id = peer_id.user_id
elif isinstance(peer_id, types.PeerChat):
peer_id = -peer_id.chat_id
elif isinstance(peer_id, types.PeerChannel):
peer_id = int("-100" + str(peer_id.channel_id))
try: # User
return self.peers_by_id[peer_id]
except KeyError:

View File

@ -40,7 +40,6 @@ class BaseClient:
platform.release()
)
SYSTEM_LANG_CODE = "en"
LANG_CODE = "en"
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/joinchat/)([\w-]+)$")
@ -59,7 +58,7 @@ class BaseClient:
5: "document",
8: "sticker",
9: "audio",
10: "gif",
10: "animation",
13: "video_note"
}

View File

@ -81,7 +81,8 @@ ENTITIES = {
types.MessageEntityCode.ID: "code",
types.MessageEntityPre.ID: "pre",
types.MessageEntityTextUrl.ID: "text_link",
types.MessageEntityMentionName.ID: "text_mention"
types.MessageEntityMentionName.ID: "text_mention",
types.MessageEntityPhone.ID: "phone_number"
}
@ -92,18 +93,20 @@ def parse_entities(entities: list, users: dict) -> list:
entity_type = ENTITIES.get(entity.ID, None)
if entity_type:
output_entities.append(pyrogram_types.MessageEntity(
type=entity_type,
offset=entity.offset,
length=entity.length,
url=getattr(entity, "url", None),
user=parse_user(
users.get(
getattr(entity, "user_id", None),
None
output_entities.append(
pyrogram_types.MessageEntity(
type=entity_type,
offset=entity.offset,
length=entity.length,
url=getattr(entity, "url", None),
user=parse_user(
users.get(
getattr(entity, "user_id", None),
None
)
)
)
))
)
return output_entities
@ -305,7 +308,7 @@ async def parse_messages(
venue = None
audio = None
voice = None
gif = None
animation = None
video = None
video_note = None
sticker = None
@ -387,7 +390,8 @@ async def parse_messages(
),
title=media.title,
address=media.address,
foursquare_id=media.venue_id or None
foursquare_id=media.venue_id or None,
foursquare_type=media.venue_type
)
elif isinstance(media, types.MessageMediaDocument):
doc = media.document
@ -444,7 +448,7 @@ async def parse_messages(
elif types.DocumentAttributeAnimated in attributes:
video_attributes = attributes.get(types.DocumentAttributeVideo, None)
gif = pyrogram_types.GIF(
animation = pyrogram_types.Animation(
file_id=encode(
pack(
"<iiqq",
@ -596,7 +600,7 @@ async def parse_messages(
venue=venue,
audio=audio,
voice=voice,
gif=gif,
animation=animation,
video=video,
video_note=video_note,
sticker=sticker,

View File

@ -19,10 +19,32 @@
import re
from .filter import Filter
from ..types.reply_markup import InlineKeyboardMarkup, ReplyKeyboardMarkup
from ..types.bots import InlineKeyboardMarkup, ReplyKeyboardMarkup
def build(name: str, func: callable, **kwargs) -> type:
def create(name: str, func: callable, **kwargs) -> type:
"""Use this method to create a Filter.
Custom filters give you extra control over which updates are allowed or not to be processed by your handlers.
Args:
name (``str``):
Your filter's name. Can be anything you like.
func (``callable``):
A function that accepts two arguments *(filter, update)* and returns a Boolean: True if the update should be
handled, False otherwise.
The "update" argument type will vary depending on which `Handler <Handlers.html>`_ is coming from.
For example, in a :obj:`MessageHandler <pyrogram.MessageHandler>` the update type will be
a :obj:`Message <pyrogram.Message>`; in a :obj:`CallbackQueryHandler <pyrogram.CallbackQueryHandler>` the
update type will be a :obj:`CallbackQuery <pyrogram.CallbackQuery>`. Your function body can then access the
incoming update and decide whether to allow it or not.
**kwargs (``any``, *optional*):
Any keyword argument you would like to pass. Useful for custom filters that accept parameters (e.g.:
:meth:`Filters.command`, :meth:`Filters.regex`).
"""
# TODO: unpack kwargs using **kwargs into the dict itself. For Python 3.5+ only
d = {"__call__": func}
d.update(kwargs)
@ -30,112 +52,118 @@ def build(name: str, func: callable, **kwargs) -> type:
class Filters:
"""This class provides access to all Filters available in Pyrogram.
Filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`."""
"""This class provides access to all library-defined Filters available in Pyrogram.
bot = build("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
The Filters listed here are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>` only.
At the moment, if you want to filter updates coming from different `Handlers <Handlers.html>`_ you have to create
your own filters with :meth:`Filters.create` and use them in the same way.
"""
create = create
bot = create("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
"""Filter messages coming from bots"""
incoming = build("Incoming", lambda _, m: not m.outgoing)
incoming = create("Incoming", lambda _, m: not m.outgoing)
"""Filter incoming messages."""
outgoing = build("Outgoing", lambda _, m: m.outgoing)
outgoing = create("Outgoing", lambda _, m: m.outgoing)
"""Filter outgoing messages."""
text = build("Text", lambda _, m: bool(m.text))
text = create("Text", lambda _, m: bool(m.text))
"""Filter text messages."""
reply = build("Reply", lambda _, m: bool(m.reply_to_message))
reply = create("Reply", lambda _, m: bool(m.reply_to_message))
"""Filter messages that are replies to other messages."""
forwarded = build("Forwarded", lambda _, m: bool(m.forward_date))
forwarded = create("Forwarded", lambda _, m: bool(m.forward_date))
"""Filter messages that are forwarded."""
caption = build("Caption", lambda _, m: bool(m.caption))
caption = create("Caption", lambda _, m: bool(m.caption))
"""Filter media messages that contain captions."""
edited = build("Edited", lambda _, m: bool(m.edit_date))
edited = create("Edited", lambda _, m: bool(m.edit_date))
"""Filter edited messages."""
audio = build("Audio", lambda _, m: bool(m.audio))
audio = create("Audio", lambda _, m: bool(m.audio))
"""Filter messages that contain :obj:`Audio <pyrogram.api.types.pyrogram.Audio>` objects."""
document = build("Document", lambda _, m: bool(m.document))
document = create("Document", lambda _, m: bool(m.document))
"""Filter messages that contain :obj:`Document <pyrogram.api.types.pyrogram.Document>` objects."""
photo = build("Photo", lambda _, m: bool(m.photo))
photo = create("Photo", lambda _, m: bool(m.photo))
"""Filter messages that contain :obj:`Photo <pyrogram.api.types.pyrogram.PhotoSize>` objects."""
sticker = build("Sticker", lambda _, m: bool(m.sticker))
sticker = create("Sticker", lambda _, m: bool(m.sticker))
"""Filter messages that contain :obj:`Sticker <pyrogram.api.types.pyrogram.Sticker>` objects."""
gif = build("GIF", lambda _, m: bool(m.gif))
"""Filter messages that contain :obj:`GIF <pyrogram.api.types.pyrogram.GIF>` objects."""
animation = create("GIF", lambda _, m: bool(m.animation))
"""Filter messages that contain :obj:`Animation <pyrogram.api.types.pyrogram.Animation>` objects."""
video = build("Video", lambda _, m: bool(m.video))
video = create("Video", lambda _, m: bool(m.video))
"""Filter messages that contain :obj:`Video <pyrogram.api.types.pyrogram.Video>` objects."""
voice = build("Voice", lambda _, m: bool(m.voice))
voice = create("Voice", lambda _, m: bool(m.voice))
"""Filter messages that contain :obj:`Voice <pyrogram.api.types.pyrogram.Voice>` note objects."""
video_note = build("Voice", lambda _, m: bool(m.video_note))
video_note = create("Voice", lambda _, m: bool(m.video_note))
"""Filter messages that contain :obj:`VideoNote <pyrogram.api.types.pyrogram.VideoNote>` objects."""
contact = build("Contact", lambda _, m: bool(m.contact))
contact = create("Contact", lambda _, m: bool(m.contact))
"""Filter messages that contain :obj:`Contact <pyrogram.api.types.pyrogram.Contact>` objects."""
location = build("Location", lambda _, m: bool(m.location))
location = create("Location", lambda _, m: bool(m.location))
"""Filter messages that contain :obj:`Location <pyrogram.api.types.pyrogram.Location>` objects."""
venue = build("Venue", lambda _, m: bool(m.venue))
venue = create("Venue", lambda _, m: bool(m.venue))
"""Filter messages that contain :obj:`Venue <pyrogram.api.types.pyrogram.Venue>` objects."""
private = build("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
private = create("Private", lambda _, m: bool(m.chat and m.chat.type == "private"))
"""Filter messages sent in private chats."""
group = build("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
group = create("Group", lambda _, m: bool(m.chat and m.chat.type in {"group", "supergroup"}))
"""Filter messages sent in group or supergroup chats."""
channel = build("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
channel = create("Channel", lambda _, m: bool(m.chat and m.chat.type == "channel"))
"""Filter messages sent in channels."""
new_chat_members = build("NewChatMembers", lambda _, m: bool(m.new_chat_members))
new_chat_members = create("NewChatMembers", lambda _, m: bool(m.new_chat_members))
"""Filter service messages for new chat members."""
left_chat_member = build("LeftChatMember", lambda _, m: bool(m.left_chat_member))
left_chat_member = create("LeftChatMember", lambda _, m: bool(m.left_chat_member))
"""Filter service messages for members that left the chat."""
new_chat_title = build("NewChatTitle", lambda _, m: bool(m.new_chat_title))
new_chat_title = create("NewChatTitle", lambda _, m: bool(m.new_chat_title))
"""Filter service messages for new chat titles."""
new_chat_photo = build("NewChatPhoto", lambda _, m: bool(m.new_chat_photo))
new_chat_photo = create("NewChatPhoto", lambda _, m: bool(m.new_chat_photo))
"""Filter service messages for new chat photos."""
delete_chat_photo = build("DeleteChatPhoto", lambda _, m: bool(m.delete_chat_photo))
delete_chat_photo = create("DeleteChatPhoto", lambda _, m: bool(m.delete_chat_photo))
"""Filter service messages for deleted photos."""
group_chat_created = build("GroupChatCreated", lambda _, m: bool(m.group_chat_created))
group_chat_created = create("GroupChatCreated", lambda _, m: bool(m.group_chat_created))
"""Filter service messages for group chat creations."""
supergroup_chat_created = build("SupergroupChatCreated", lambda _, m: bool(m.supergroup_chat_created))
supergroup_chat_created = create("SupergroupChatCreated", lambda _, m: bool(m.supergroup_chat_created))
"""Filter service messages for supergroup chat creations."""
channel_chat_created = build("ChannelChatCreated", lambda _, m: bool(m.channel_chat_created))
channel_chat_created = create("ChannelChatCreated", lambda _, m: bool(m.channel_chat_created))
"""Filter service messages for channel chat creations."""
migrate_to_chat_id = build("MigrateToChatId", lambda _, m: bool(m.migrate_to_chat_id))
migrate_to_chat_id = create("MigrateToChatId", lambda _, m: bool(m.migrate_to_chat_id))
"""Filter service messages that contain migrate_to_chat_id."""
migrate_from_chat_id = build("MigrateFromChatId", lambda _, m: bool(m.migrate_from_chat_id))
migrate_from_chat_id = create("MigrateFromChatId", lambda _, m: bool(m.migrate_from_chat_id))
"""Filter service messages that contain migrate_from_chat_id."""
pinned_message = build("PinnedMessage", lambda _, m: bool(m.pinned_message))
pinned_message = create("PinnedMessage", lambda _, m: bool(m.pinned_message))
"""Filter service messages for pinned messages."""
reply_keyboard = build("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
reply_keyboard = create("ReplyKeyboard", lambda _, m: isinstance(m.reply_markup, ReplyKeyboardMarkup))
"""Filter messages containing reply keyboard markups"""
inline_keyboard = build("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
"""Filter messages containing inline keyboard markups"""
@staticmethod
@ -174,7 +202,7 @@ class Filters:
return bool(m.command)
return build(
return create(
"Command",
f,
c={command if case_sensitive
@ -206,7 +234,7 @@ class Filters:
m.matches = [i for i in _.p.finditer(m.text or "")]
return bool(m.matches)
return build("Regex", f, p=re.compile(pattern, flags))
return create("Regex", f, p=re.compile(pattern, flags))
@staticmethod
def user(user: int or str or list):
@ -216,7 +244,7 @@ class Filters:
user (``int`` | ``str`` | ``list``):
The user or list of user IDs (int) or usernames (str) the filter should look for.
"""
return build(
return create(
"User",
lambda _, m: bool(m.from_user
and (m.from_user.id in _.u
@ -237,7 +265,7 @@ class Filters:
chat (``int`` | ``str`` | ``list``):
The chat or list of chat IDs (int) or usernames (str) the filter should look for.
"""
return build(
return create(
"Chat",
lambda _, m: bool(m.chat
and (m.chat.id in _.c
@ -250,7 +278,7 @@ class Filters:
)
)
service = build(
service = create(
"Service",
lambda _, m: bool(
Filters.new_chat_members(m)
@ -268,7 +296,7 @@ class Filters:
)
"""Filter all service messages."""
media = build(
media = create(
"Media",
lambda _, m: bool(
Filters.audio(m)
@ -276,7 +304,7 @@ class Filters:
or Filters.photo(m)
or Filters.sticker(m)
or Filters.video(m)
or Filters.gif(m)
or Filters.animation(m)
or Filters.voice(m)
or Filters.video_note(m)
or Filters.contact(m)

View File

@ -20,10 +20,10 @@ from .bots import Bots
from .chats import Chats
from .contacts import Contacts
from .decorators import Decorators
from .download_media import DownloadMedia
from .messages import Messages
from .password import Password
from .users import Users
from .utilities import Utilities
class Methods(
@ -32,7 +32,7 @@ class Methods(
Password,
Chats,
Users,
DownloadMedia,
Utilities,
Messages,
Decorators
):

View File

@ -33,7 +33,6 @@ class RequestCallbackAnswer(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
The message id the inline keyboard is attached on.

View File

@ -35,7 +35,6 @@ class SendInlineBotResult(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
query_id (``int``):
Unique identifier for the answered query.

View File

@ -19,7 +19,9 @@
from .delete_chat_photo import DeleteChatPhoto
from .export_chat_invite_link import ExportChatInviteLink
from .get_chat import GetChat
from .get_chat_member import GetChatMember
from .get_chat_members import GetChatMembers
from .get_dialogs import GetDialogs
from .join_chat import JoinChat
from .kick_chat_member import KickChatMember
from .leave_chat import LeaveChat
@ -43,11 +45,13 @@ class Chats(
RestrictChatMember,
PromoteChatMember,
GetChatMembers,
GetChatMember,
SetChatPhoto,
DeleteChatPhoto,
SetChatTitle,
SetChatDescription,
PinChatMessage,
UnpinChatMessage
UnpinChatMessage,
GetDialogs
):
pass

View File

@ -33,7 +33,6 @@ class DeleteChatPhoto(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
True on success.

View File

@ -28,7 +28,6 @@ class GetChat(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.

View File

@ -0,0 +1,75 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from pyrogram.api import functions, types, errors
from ...ext import BaseClient, utils
class GetChatMember(BaseClient):
def get_chat_member(self,
chat_id: int or str,
user_id: int or str):
"""Use this method to get information about one member of a chat.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
user_id (``int`` | ``str``)::
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
Returns:
On success, a :obj:`ChatMember <pyrogram.ChatMember>` object is returned.
Raises:
:class:`Error <pyrogram.Error>`
"""
chat_id = self.resolve_peer(chat_id)
user_id = self.resolve_peer(user_id)
if isinstance(chat_id, types.InputPeerChat):
full_chat = self.send(
functions.messages.GetFullChat(
chat_id=chat_id.chat_id
)
)
for member in utils.parse_chat_members(full_chat).chat_members:
if member.user.id == user_id.user_id:
return member
else:
raise errors.UserNotParticipant
elif isinstance(chat_id, types.InputPeerChannel):
r = self.send(
functions.channels.GetParticipant(
channel=chat_id,
user_id=user_id
)
)
return utils.parse_chat_members(
types.channels.ChannelParticipants(
count=1,
participants=[r.participant],
users=r.users
)
).chat_members[0]
else:
raise ValueError("The chat_id \"{}\" belongs to a user".format(chat_id))

View File

@ -36,6 +36,42 @@ class GetChatMembers(BaseClient):
limit: int = 200,
query: str = "",
filter: str = Filters.ALL):
"""Use this method to get the members list of a chat.
A chat can be either a basic group, a supergroup or a channel.
You must be admin to retrieve the members (also known as "subscribers") list of a channel.
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
offset (``int``, *optional*):
Sequential number of the first member to be returned.
Defaults to 0 [1]_.
limit (``int``, *optional*):
Limits the number of members to be retrieved.
Defaults to 200, which is also the maximum limit allowed per method call.
query (``str``, *optional*):
Query string to filter members based on their display names and usernames.
Defaults to "" (empty string) [2]_.
filter (``str``, *optional*):
Filter used to select the kind of members you want to retrieve. Only applicable for supergroups
and channels. It can be any of the followings:
*"all"* - all kind of members,
*"kicked"* - kicked (banned) members only,
*"restricted"* - restricted members only,
*"bots"* - bots only,
*"recent"* - recent members only,
*"administrators"* - chat administrators only.
Defaults to *"all"*.
.. [1] On supergroups and channels you can get up to 10,000 members for a single query string.
.. [2] A query string is applicable only for *"all"*, *"kicked"* and *"restricted"* filters only.
"""
peer = await self.resolve_peer(chat_id)
if isinstance(peer, types.InputPeerChat):

View File

@ -22,19 +22,41 @@ from ...ext import BaseClient, utils
class GetDialogs(BaseClient):
# TODO docstrings
def get_dialogs(self,
offset_dialogs=None,
limit: int = 100,
pinned_only: bool = False):
"""Use this method to get the user's dialogs
You can get up to 100 dialogs at once.
Args:
limit (``str``, *optional*):
Limits the number of dialogs to be retrieved.
Defaults to 100
pinned_only (``bool``, *optional*):
Pass True if you want to get only pinned dialogs.
Defaults to False.
offset_dialogs (:obj:`Dialogs`):
Pass the previous dialogs object to retrieve the next dialogs chunk starting from the last dialog.
Defaults to None (start from the beginning).
Returns:
On success, a :obj:`Dialogs` object is returned.
Raises:
:class:`Error`
"""
async def get_dialogs(self,
limit: int = 100,
pinned_only: bool = False,
last_chunk=None):
if pinned_only:
r = await self.send(functions.messages.GetPinnedDialogs())
else:
offset_date = 0
if last_chunk:
for dialog in reversed(last_chunk.dialogs):
if offset_dialogs:
for dialog in reversed(offset_dialogs.dialogs):
top_message = dialog.top_message
if top_message:
@ -92,7 +114,8 @@ class GetDialogs(BaseClient):
top_message=messages.get(chat_id),
unread_messages_count=dialog.unread_count,
unread_mentions_count=dialog.unread_mentions_count,
unread_mark=dialog.unread_mark
unread_mark=dialog.unread_mark,
is_pinned=dialog.pinned
)
)

View File

@ -38,7 +38,6 @@ class KickChatMember(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
user_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target user.

View File

@ -29,7 +29,6 @@ class PinChatMessage(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
Identifier of a message to pin.

View File

@ -39,7 +39,6 @@ class PromoteChatMember(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
user_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target user.

View File

@ -36,7 +36,6 @@ class RestrictChatMember(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
user_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target user.

View File

@ -28,7 +28,6 @@ class SetChatDescription(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
description (``str``):
New chat description, 0-255 characters.

View File

@ -37,7 +37,6 @@ class SetChatPhoto(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
photo (``str``):
New chat photo. You can pass a :class:`Photo` id or a file path to upload a new photo.

View File

@ -33,7 +33,6 @@ class SetChatTitle(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
title (``str``):
New chat title, 1-255 characters.

View File

@ -31,7 +31,6 @@ class UnbanChatMember(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
user_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target user.

View File

@ -29,7 +29,6 @@ class UnpinChatMessage(BaseClient):
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For a private channel/supergroup you can use its *t.me/joinchat/* link.
Returns:
True on success.

View File

@ -18,17 +18,17 @@
from .delete_messages import DeleteMessages
from .edit_message_caption import EditMessageCaption
from .edit_message_media import EditMessageMedia
from .edit_message_reply_markup import EditMessageReplyMarkup
from .edit_message_text import EditMessageText
from .forward_messages import ForwardMessages
from .get_dialogs import GetDialogs
from .get_history import GetHistory
from .get_messages import GetMessages
from .send_animation import SendAnimation
from .send_audio import SendAudio
from .send_chat_action import SendChatAction
from .send_contact import SendContact
from .send_document import SendDocument
from .send_gif import SendGIF
from .send_location import SendLocation
from .send_media_group import SendMediaGroup
from .send_message import SendMessage
@ -44,16 +44,16 @@ class Messages(
DeleteMessages,
EditMessageCaption,
EditMessageReplyMarkup,
EditMessageMedia,
EditMessageText,
ForwardMessages,
GetHistory,
GetMessages,
GetDialogs,
SendAudio,
SendChatAction,
SendContact,
SendDocument,
SendGIF,
SendAnimation,
SendLocation,
SendMediaGroup,
SendMessage,

View File

@ -38,7 +38,6 @@ class DeleteMessages(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_ids (``iterable``):
A list of Message identifiers to delete or a single message id.

View File

@ -34,7 +34,6 @@ class EditMessageCaption(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
Message identifier in the chat specified in chat_id.

View File

@ -0,0 +1,264 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
import binascii
import mimetypes
import os
import struct
from pyrogram.api import functions, types
from pyrogram.api.errors import FileIdInvalid
from pyrogram.client.ext import BaseClient, utils
from pyrogram.client.types import (
InputMediaPhoto, InputMediaVideo, InputMediaAudio,
InputMediaAnimation
)
class EditMessageMedia(BaseClient):
def edit_message_media(self,
chat_id: int or str,
message_id: int,
media,
reply_markup=None):
style = self.html if media.parse_mode.lower() == "html" else self.markdown
caption = media.caption
if isinstance(media, InputMediaPhoto):
if os.path.exists(media.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedPhoto(
file=self.save_file(media.media)
)
)
)
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=media.photo.id,
access_hash=media.photo.access_hash
)
)
elif media.media.startswith("http"):
media = types.InputMediaPhotoExternal(
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 2:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaPhoto(
id=types.InputPhoto(
id=unpacked[2],
access_hash=unpacked[3]
)
)
if isinstance(media, InputMediaVideo):
if os.path.exists(media.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=self.save_file(media.media),
attributes=[
types.DocumentAttributeVideo(
supports_streaming=media.supports_streaming or None,
duration=media.duration,
w=media.width,
h=media.height
),
types.DocumentAttributeFilename(os.path.basename(media.media))
]
)
)
)
media = types.InputMediaDocument(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash
)
)
elif media.media.startswith("http"):
media = types.InputMediaDocumentExternal(
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 4:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3]
)
)
if isinstance(media, InputMediaAudio):
if os.path.exists(media.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "audio/mpeg"),
file=self.save_file(media.media),
attributes=[
types.DocumentAttributeAudio(
duration=media.duration,
performer=media.performer,
title=media.title
),
types.DocumentAttributeFilename(os.path.basename(media.media))
]
)
)
)
media = types.InputMediaDocument(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash
)
)
elif media.media.startswith("http"):
media = types.InputMediaDocumentExternal(
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 9:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3]
)
)
if isinstance(media, InputMediaAnimation):
if os.path.exists(media.media):
media = self.send(
functions.messages.UploadMedia(
peer=self.resolve_peer(chat_id),
media=types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=self.save_file(media.media),
attributes=[
types.DocumentAttributeVideo(
supports_streaming=True,
duration=media.duration,
w=media.width,
h=media.height
),
types.DocumentAttributeFilename(os.path.basename(media.media)),
types.DocumentAttributeAnimated()
]
)
)
)
media = types.InputMediaDocument(
id=types.InputDocument(
id=media.document.id,
access_hash=media.document.access_hash
)
)
elif media.media.startswith("http"):
media = types.InputMediaDocumentExternal(
url=media.media
)
else:
try:
decoded = utils.decode(media.media)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
raise FileIdInvalid from None
else:
if unpacked[0] != 10:
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
if media_type:
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
else:
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
media = types.InputMediaDocument(
id=types.InputDocument(
id=unpacked[2],
access_hash=unpacked[3]
)
)
r = self.send(
functions.messages.EditMessage(
peer=self.resolve_peer(chat_id),
id=message_id,
reply_markup=reply_markup.write() if reply_markup else None,
media=media,
**style.parse(caption)
)
)
for i in r.updates:
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
return utils.parse_messages(
self, i.message,
{i.id: i for i in r.users},
{i.id: i for i in r.chats}
)

View File

@ -32,7 +32,6 @@ class EditMessageReplyMarkup(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
Message identifier in the chat specified in chat_id.

View File

@ -35,7 +35,6 @@ class EditMessageText(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_id (``int``):
Message identifier in the chat specified in chat_id.

View File

@ -33,13 +33,11 @@ class ForwardMessages(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
from_chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the source chat where the original message was sent.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_ids (``iterable``):
A list of Message identifiers in the chat specified in *from_chat_id* or a single message id.

View File

@ -37,7 +37,6 @@ class GetHistory(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
offset (``int``, *optional*)
Sequential number of the first message to be returned.

View File

@ -33,7 +33,6 @@ class GetMessages(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
message_ids (``iterable``):
A list of Message identifiers in the chat specified in *chat_id* or a single message id, as integer.

View File

@ -26,38 +26,37 @@ from pyrogram.api.errors import FileIdInvalid, FilePartMissing
from pyrogram.client.ext import BaseClient, utils
class SendGIF(BaseClient):
async def send_gif(self,
chat_id: int or str,
gif: str,
caption: str = "",
parse_mode: str = "",
duration: int = 0,
width: int = 0,
height: int = 0,
thumb: str = None,
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None,
progress: callable = None,
progress_args: tuple = ()):
"""Use this method to send GIF files.
class SendAnimation(BaseClient):
asyncdef send_animation(self,
chat_id: int or str,
animation: str,
caption: str = "",
parse_mode: str = "",
duration: int = 0,
width: int = 0,
height: int = 0,
thumb: str = None,
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None,
progress: callable = None,
progress_args: tuple = ()):
"""Use this method to send animation files(animation or H.264/MPEG-4 AVC video without sound).
Args:
chat_id (``int`` | ``str``):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
gif (``str``):
GIF to send.
Pass a file_id as string to send a GIF that exists on the Telegram servers,
pass an HTTP URL as a string for Telegram to get a GIF from the Internet, or
pass a file path as string to upload a new GIF that exists on your local machine.
animation (``str``):
Animation to send.
Pass a file_id as string to send an animation that exists on the Telegram servers,
pass an HTTP URL as a string for Telegram to get an animation from the Internet, or
pass a file path as string to upload a new animation that exists on your local machine.
caption (``str``, *optional*):
GIF caption, 0-200 characters.
Animation caption, 0-200 characters.
parse_mode (``str``, *optional*):
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
@ -65,16 +64,16 @@ class SendGIF(BaseClient):
Defaults to Markdown.
duration (``int``, *optional*):
Duration of sent GIF in seconds.
Duration of sent animation in seconds.
width (``int``, *optional*):
GIF width.
Animation width.
height (``int``, *optional*):
GIF height.
Animation height.
thumb (``str``, *optional*):
GIF thumbnail.
Animation thumbnail.
Pass a file path as string to send an image that exists on your local machine.
Thumbnail should have 90 or less pixels of width and 90 or less pixels of height.
@ -121,9 +120,9 @@ class SendGIF(BaseClient):
file = None
style = self.html if parse_mode.lower() == "html" else self.markdown
if os.path.exists(gif):
if os.path.exists(animation):
thumb = None if thumb is None else await self.save_file(thumb)
file = await self.save_file(gif, progress=progress, progress_args=progress_args)
file = await self.save_file(animation, progress=progress, progress_args=progress_args)
media = types.InputMediaUploadedDocument(
mime_type=mimetypes.types_map[".mp4"],
file=file,
@ -135,17 +134,17 @@ class SendGIF(BaseClient):
w=width,
h=height
),
types.DocumentAttributeFilename(os.path.basename(gif)),
types.DocumentAttributeFilename(os.path.basename(animation)),
types.DocumentAttributeAnimated()
]
)
elif gif.startswith("http"):
elif animation.startswith("http"):
media = types.InputMediaDocumentExternal(
url=gif
url=animation
)
else:
try:
decoded = utils.decode(gif)
decoded = utils.decode(animation)
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
unpacked = struct.unpack(fmt, decoded)
except (AssertionError, binascii.Error, struct.error):
@ -180,7 +179,7 @@ class SendGIF(BaseClient):
)
)
except FilePartMissing as e:
await self.save_file(gif, file_id=file.id, file_part=e.x)
await self.save_file(animation, file_id=file.id, file_part=e.x)
else:
for i in r.updates:
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):

View File

@ -49,7 +49,6 @@ class SendAudio(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
audio (``str``):
Audio file to send.

View File

@ -32,7 +32,6 @@ class SendChatAction(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
action (:obj:`ChatAction <pyrogram.ChatAction>` | ``str``):
Type of action to broadcast.

View File

@ -36,7 +36,6 @@ class SendContact(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
phone_number (``str``):
Contact's phone number.
@ -48,7 +47,7 @@ class SendContact(BaseClient):
Contact's last name.
vcard (``str``, *optional*):
Contact's vCard information.
Additional data about the contact in the form of a vCard, 0-2048 bytes
disable_notification (``bool``, *optional*):
Sends the message silently.

View File

@ -44,7 +44,6 @@ class SendDocument(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
document (``str``):
File to send.

View File

@ -35,7 +35,6 @@ class SendLocation(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
latitude (``float``):
Latitude of the location.

View File

@ -44,7 +44,6 @@ class SendMediaGroup(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
media (``list``):
A list containing either :obj:`InputMediaPhoto <pyrogram.InputMediaPhoto>` or

View File

@ -37,7 +37,6 @@ class SendMessage(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
text (``str``):
Text of the message to be sent.
@ -62,7 +61,7 @@ class SendMessage(BaseClient):
instructions to remove reply keyboard or to force a reply from the user.
Returns:
On success, the sent Message is returned.
On success, the sent :obj:`Message` is returned.
Raises:
:class:`Error <pyrogram.Error>`

View File

@ -44,7 +44,6 @@ class SendPhoto(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
photo (``str``):
Photo to send.

View File

@ -41,7 +41,6 @@ class SendSticker(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
sticker (``str``):
Sticker to send.

View File

@ -22,15 +22,15 @@ from pyrogram.client.ext import BaseClient, utils
class SendVenue(BaseClient):
async def send_venue(self,
chat_id: int or str,
latitude: float,
longitude: float,
title: str,
address: str,
foursquare_id: str = "",
disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None):
chat_id: int or str,
latitude: float,
longitude: float,
title: str,
address: str,
foursquare_id: str = "",
foursquare_type: str = "",disable_notification: bool = None,
reply_to_message_id: int = None,
reply_markup=None):
"""Use this method to send information about a venue.
Args:
@ -38,7 +38,6 @@ class SendVenue(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
latitude (``float``):
Latitude of the venue.
@ -55,6 +54,10 @@ class SendVenue(BaseClient):
foursquare_id (``str``, *optional*):
Foursquare identifier of the venue.
foursquare_type (``str``, *optional*):
Foursquare type of the venue, if known.
(For example, "arts_entertainment/default", "arts_entertainment/aquarium" or "food/icecream".)
disable_notification (``bool``, *optional*):
Sends the message silently.
Users will receive a notification with no sound.
@ -84,7 +87,7 @@ class SendVenue(BaseClient):
address=address,
provider="",
venue_id=foursquare_id,
venue_type=""
venue_type=foursquare_type
),
message="",
silent=disable_notification or None,

View File

@ -49,7 +49,6 @@ class SendVideo(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
video (``str``):
Video to send.

View File

@ -44,7 +44,6 @@ class SendVideoNote(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
video_note (``str``):
Video note to send.

View File

@ -45,7 +45,6 @@ class SendVoice(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
voice (``str``):
Audio file to send.

View File

@ -32,7 +32,6 @@ class GetUserProfilePhotos(BaseClient):
Unique identifier (int) or username (str) of the target chat.
For your personal cloud (Saved Messages) you can simply use "me" or "self".
For a contact that exists in your Telegram address book you can use his phone number (str).
For a private channel/supergroup you can use its *t.me/joinchat/* link.
offset (``int``, *optional*):
Sequential number of the first photo to be returned.

View File

@ -0,0 +1,25 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from .download_media import DownloadMedia
class Utilities(
DownloadMedia
):
pass

Some files were not shown because too many files have changed in this diff Show More