mirror of
https://github.com/TeamPGM/pyrogram.git
synced 2024-11-28 00:56:19 +00:00
Merge branch 'develop' into inline-mode
# Conflicts: # compiler/api/compiler.py
This commit is contained in:
commit
8d50b86bc6
@ -97,13 +97,13 @@ Copyright & License
|
||||
<a href="https://t.me/PyrogramChat">
|
||||
Community
|
||||
</a>
|
||||
<br><br>
|
||||
<br>
|
||||
<a href="compiler/api/source/main_api.tl">
|
||||
<img src="https://img.shields.io/badge/SCHEME-LAYER%2082-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
alt="Scheme Layer">
|
||||
<img src="https://img.shields.io/badge/schema-layer%2082-eda738.svg?longCache=true&colorA=262b30"
|
||||
alt="Schema Layer">
|
||||
</a>
|
||||
<a href="https://github.com/pyrogram/tgcrypto">
|
||||
<img src="https://img.shields.io/badge/TGCRYPTO-V1.1.1-eda738.svg?longCache=true&style=for-the-badge&colorA=262b30"
|
||||
<img src="https://img.shields.io/badge/tgcrypto-v1.1.1-eda738.svg?longCache=true&colorA=262b30"
|
||||
alt="TgCrypto">
|
||||
</a>
|
||||
</p>
|
||||
|
@ -507,6 +507,7 @@ def start():
|
||||
f.write("\n 0xb0700028: \"pyrogram.client.types.Dialog\",")
|
||||
f.write("\n 0xb0700029: \"pyrogram.client.types.Dialogs\",")
|
||||
f.write("\n 0xb0700030: \"pyrogram.client.types.ChatMembers\",")
|
||||
f.write("\n 0xb0700031: \"pyrogram.client.types.UserStatus\"")
|
||||
f.write("\n 0xb0700032: \"pyrogram.client.types.InlineQuery\"")
|
||||
|
||||
f.write("\n}\n")
|
||||
|
@ -67,4 +67,5 @@ 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
|
||||
USER_NOT_PARTICIPANT The user is not a member of this chat
|
||||
CHANNEL_PRIVATE The channel/supergroup is not accessible
|
||||
CHANNEL_PRIVATE The channel/supergroup is not accessible
|
||||
MESSAGE_IDS_EMPTY The requested message doesn't exist
|
|
@ -1,4 +1,5 @@
|
||||
id message
|
||||
CHAT_WRITE_FORBIDDEN You don't have rights to send messages in this chat
|
||||
RIGHT_FORBIDDEN One or more admin rights can't be applied to this kind of chat (channel/supergroup)
|
||||
CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
|
||||
CHAT_ADMIN_INVITE_REQUIRED You don't have rights to invite other users
|
||||
MESSAGE_DELETE_FORBIDDEN You don't have rights to delete messages in this chat
|
|
@ -84,6 +84,7 @@ To get started, press the Next button.
|
||||
|
||||
resources/UpdateHandling
|
||||
resources/UsingFilters
|
||||
resources/SmartPlugins
|
||||
resources/AutoAuthorization
|
||||
resources/CustomizeSessions
|
||||
resources/TgCrypto
|
||||
|
@ -30,6 +30,7 @@ Decorators
|
||||
on_message
|
||||
on_callback_query
|
||||
on_deleted_messages
|
||||
on_user_status
|
||||
on_disconnect
|
||||
on_raw_update
|
||||
|
||||
@ -96,7 +97,8 @@ Users
|
||||
get_me
|
||||
get_users
|
||||
get_user_profile_photos
|
||||
delete_profile_photos
|
||||
set_user_profile_photo
|
||||
delete_user_profile_photos
|
||||
|
||||
Contacts
|
||||
--------
|
||||
|
@ -3,4 +3,3 @@ Filters
|
||||
|
||||
.. autoclass:: pyrogram.Filters
|
||||
:members:
|
||||
:undoc-members:
|
||||
|
@ -9,6 +9,7 @@ Handlers
|
||||
MessageHandler
|
||||
DeletedMessagesHandler
|
||||
CallbackQueryHandler
|
||||
UserStatusHandler
|
||||
DisconnectHandler
|
||||
RawUpdateHandler
|
||||
|
||||
@ -21,6 +22,9 @@ Handlers
|
||||
.. autoclass:: CallbackQueryHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: UserStatusHandler
|
||||
:members:
|
||||
|
||||
.. autoclass:: DisconnectHandler
|
||||
:members:
|
||||
|
||||
|
@ -10,6 +10,7 @@ Users & Chats
|
||||
:nosignatures:
|
||||
|
||||
User
|
||||
UserStatus
|
||||
Chat
|
||||
ChatPhoto
|
||||
ChatMember
|
||||
@ -73,6 +74,9 @@ Input Media
|
||||
.. autoclass:: User
|
||||
:members:
|
||||
|
||||
.. autoclass:: UserStatus
|
||||
:members:
|
||||
|
||||
.. autoclass:: Chat
|
||||
:members:
|
||||
|
||||
|
@ -35,11 +35,8 @@ Example:
|
||||
password="password" # (if you have one)
|
||||
)
|
||||
|
||||
app.start()
|
||||
|
||||
print(app.get_me())
|
||||
|
||||
app.stop()
|
||||
with app:
|
||||
print(app.get_me())
|
||||
|
||||
Sign Up
|
||||
-------
|
||||
@ -67,8 +64,5 @@ Example:
|
||||
last_name="" # Can be an empty string
|
||||
)
|
||||
|
||||
app.start()
|
||||
|
||||
print(app.get_me())
|
||||
|
||||
app.stop()
|
||||
with app:
|
||||
print(app.get_me())
|
||||
|
126
docs/source/resources/SmartPlugins.rst
Normal file
126
docs/source/resources/SmartPlugins.rst
Normal file
@ -0,0 +1,126 @@
|
||||
Smart Plugins
|
||||
=============
|
||||
|
||||
Pyrogram embeds a **smart** (automatic) and lightweight plugin system that is meant to further simplify the organization
|
||||
of large projects and to provide a way for creating pluggable components that can be **easily shared** across different
|
||||
Pyrogram applications with **minimal boilerplate code**.
|
||||
|
||||
.. tip::
|
||||
|
||||
Smart Plugins are completely optional and disabled by default.
|
||||
|
||||
Introduction
|
||||
------------
|
||||
|
||||
Prior to the Smart Plugin system, pluggable handlers were already possible. For example, if you wanted to modularize
|
||||
your applications, you had to do something like this...
|
||||
|
||||
.. note::
|
||||
|
||||
This is an example application that replies in private chats with two messages: one containing the same
|
||||
text message you sent and the other containing the reversed text message.
|
||||
|
||||
Example: *"Pyrogram"* replies with *"Pyrogram"* and *"margoryP"*
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
myproject/
|
||||
config.ini
|
||||
handlers.py
|
||||
main.py
|
||||
|
||||
- ``handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
def echo(client, message):
|
||||
message.reply(message.text)
|
||||
|
||||
|
||||
def echo_reversed(client, message):
|
||||
message.reply(message.text[::-1])
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client, MessageHandler, Filters
|
||||
|
||||
from handlers import echo, echo_reversed
|
||||
|
||||
app = Client("my_account")
|
||||
|
||||
app.add_handler(
|
||||
MessageHandler(
|
||||
echo,
|
||||
Filters.text & Filters.private))
|
||||
|
||||
app.add_handler(
|
||||
MessageHandler(
|
||||
echo_reversed,
|
||||
Filters.text & Filters.private),
|
||||
group=1)
|
||||
|
||||
app.run()
|
||||
|
||||
...which is already nice and doesn't add *too much* boilerplate code, but things can get boring still; you have to
|
||||
manually ``import``, manually :meth:`add_handler <pyrogram.Client.add_handler>` and manually instantiate each
|
||||
:obj:`MessageHandler <pyrogram.MessageHandler>` object because **you can't use those cool decorators** for your
|
||||
functions. So... What if you could?
|
||||
|
||||
Using Smart Plugins
|
||||
-------------------
|
||||
|
||||
Setting up your Pyrogram project to accommodate Smart Plugins is pretty straightforward:
|
||||
|
||||
#. Create a new folder to store all the plugins (e.g.: "plugins").
|
||||
#. Put your files full of plugins inside.
|
||||
#. Enable plugins in your Client.
|
||||
|
||||
.. note::
|
||||
|
||||
This is the same example application `as shown above <#introduction>`_, written using the Smart Plugin system.
|
||||
|
||||
.. code-block:: text
|
||||
:emphasize-lines: 2, 3
|
||||
|
||||
myproject/
|
||||
plugins/
|
||||
handlers.py
|
||||
config.ini
|
||||
main.py
|
||||
|
||||
- ``plugins/handlers.py``
|
||||
|
||||
.. code-block:: python
|
||||
:emphasize-lines: 4, 9
|
||||
|
||||
from pyrogram import Client, Filters
|
||||
|
||||
|
||||
@Client.on_message(Filters.text & Filters.private)
|
||||
def echo(client, message):
|
||||
message.reply(message.text)
|
||||
|
||||
|
||||
@Client.on_message(Filters.text & Filters.private, group=1)
|
||||
def echo_reversed(client, message):
|
||||
message.reply(message.text[::-1])
|
||||
|
||||
- ``main.py``
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
from pyrogram import Client
|
||||
|
||||
Client("my_account", plugins_dir="plugins").run()
|
||||
|
||||
The first important thing to note is the new ``plugins`` folder, whose name is passed to the the ``plugins_dir``
|
||||
parameter when creating a :obj:`Client <pyrogram.Client>` in the ``main.py`` file — you can put *any python file* in
|
||||
there and each file can contain *any decorated function* (handlers) with only one limitation: within a single plugin
|
||||
file you must use different names for each decorated function. Your Pyrogram Client instance will **automatically**
|
||||
scan the folder upon creation to search for valid handlers and register them for you.
|
||||
|
||||
Then you'll notice you can now use decorators. That's right, you can apply the usual decorators to your callback
|
||||
functions in a static way, i.e. **without having the Client instance around**: simply use ``@Client`` (Client class)
|
||||
instead of the usual ``@app`` (Client instance) namespace and things will work just the same.
|
@ -14,17 +14,17 @@ by following the instructions at https://pip.pypa.io/en/latest/installing/.
|
||||
Install Pyrogram
|
||||
----------------
|
||||
|
||||
- The easiest way to install and upgrade Pyrogram is by using **pip**:
|
||||
- The easiest way to install and upgrade Pyrogram to its latest stable version is by using **pip**:
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install --upgrade pyrogram
|
||||
|
||||
- or, with TgCrypto_ (recommended):
|
||||
- or, with TgCrypto_ as extra requirement (recommended):
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install --upgrade pyrogram[tgcrypto]
|
||||
$ pip3 install --upgrade pyrogram[fast]
|
||||
|
||||
Bleeding Edge
|
||||
-------------
|
||||
@ -32,21 +32,57 @@ Bleeding Edge
|
||||
If you want the latest development version of Pyrogram, you can install it straight from the develop_
|
||||
branch using this command (you might need to install **git** first):
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git
|
||||
|
||||
Asynchronous
|
||||
------------
|
||||
|
||||
Pyrogram heavily depends on IO-bound network code (it's a cloud-based messaging client library after all), and here's
|
||||
where asyncio shines the most by providing extra performance while running on a single OS-level thread only.
|
||||
|
||||
**A fully asynchronous variant of Pyrogram is therefore available** (Python 3.5+ required).
|
||||
Use this command to install:
|
||||
|
||||
.. code-block:: text
|
||||
|
||||
$ pip3 install --upgrade git+https://github.com/pyrogram/pyrogram.git@asyncio
|
||||
|
||||
|
||||
Pyrogram API remains the same and features are kept up to date from the non-async, default develop branch, but you
|
||||
are obviously required Python asyncio knowledge in order to take full advantage of it.
|
||||
|
||||
|
||||
.. tip::
|
||||
|
||||
The idea to turn Pyrogram fully asynchronous is still under consideration, but is wise to expect that in future this
|
||||
would be the one and only way to work with Pyrogram.
|
||||
|
||||
You can start using Pyrogram Async variant right now as an excuse to learn more about asynchronous programming and
|
||||
do experiments with it!
|
||||
|
||||
.. raw:: html
|
||||
|
||||
<script async
|
||||
src="https://telegram.org/js/telegram-widget.js?4"
|
||||
data-telegram-post="Pyrogram/4"
|
||||
data-width="100%">
|
||||
</script>
|
||||
|
||||
.. centered:: Subscribe to `@Pyrogram <https://t.me/Pyrogram>`_ for news and announcements
|
||||
|
||||
Verifying
|
||||
---------
|
||||
|
||||
To verify that Pyrogram is correctly installed, open a Python shell and import it.
|
||||
If no error shows up you are good to go.
|
||||
|
||||
.. code-block:: bash
|
||||
.. code-block:: python
|
||||
|
||||
>>> import pyrogram
|
||||
>>> pyrogram.__version__
|
||||
'0.8.0'
|
||||
'0.9.1'
|
||||
|
||||
.. _TgCrypto: https://docs.pyrogram.ml/resources/TgCrypto
|
||||
.. _develop: http://github.com/pyrogram/pyrogram
|
||||
.. _develop: http://github.com/pyrogram/pyrogram
|
||||
|
@ -23,13 +23,13 @@ __copyright__ = "Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance
|
||||
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||
)
|
||||
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
||||
__version__ = "0.8.1dev1"
|
||||
__version__ = "0.9.2.dev1"
|
||||
|
||||
from .api.errors import Error
|
||||
from .client.types import (
|
||||
Audio, Chat, ChatMember, ChatMembers, ChatPhoto, Contact, Document, InputMediaPhoto,
|
||||
InputMediaVideo, InputMediaDocument, InputMediaAudio, InputMediaAnimation, InputPhoneContact,
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User,
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, Update, User, UserStatus,
|
||||
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove,
|
||||
InlineQuery, InlineQueryResultArticle, InlineQueryResultPhoto, InputTextMessageContent, InlineQueryResultCachedAudio
|
||||
@ -37,5 +37,5 @@ from .client.types import (
|
||||
from .client import (
|
||||
Client, ChatAction, ParseMode, Emoji,
|
||||
MessageHandler, DeletedMessagesHandler, CallbackQueryHandler,
|
||||
RawUpdateHandler, DisconnectHandler, Filters
|
||||
RawUpdateHandler, DisconnectHandler, UserStatusHandler, Filters
|
||||
)
|
||||
|
@ -22,5 +22,5 @@ from .filters import Filters
|
||||
from .handlers import (
|
||||
MessageHandler, DeletedMessagesHandler,
|
||||
CallbackQueryHandler, RawUpdateHandler,
|
||||
DisconnectHandler
|
||||
DisconnectHandler, UserStatusHandler
|
||||
)
|
||||
|
@ -33,6 +33,8 @@ import time
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from hashlib import sha256, md5
|
||||
from importlib import import_module
|
||||
from pathlib import Path
|
||||
from signal import signal, SIGINT, SIGTERM, SIGABRT
|
||||
from threading import Thread
|
||||
|
||||
@ -45,6 +47,7 @@ from pyrogram.api.errors import (
|
||||
PasswordHashInvalid, FloodWait, PeerIdInvalid, FirstnameInvalid, PhoneNumberBanned,
|
||||
VolumeLocNotFound, UserMigrate, FileIdInvalid, ChannelPrivate)
|
||||
from pyrogram.client.handlers import DisconnectHandler
|
||||
from pyrogram.client.handlers.handler import Handler
|
||||
from pyrogram.crypto import AES
|
||||
from pyrogram.session import Auth, Session
|
||||
from .dispatcher import Dispatcher
|
||||
@ -140,6 +143,11 @@ class Client(Methods, BaseClient):
|
||||
|
||||
config_file (``str``, *optional*):
|
||||
Path of the configuration file. Defaults to ./config.ini
|
||||
|
||||
plugins_dir (``str``, *optional*):
|
||||
Define a custom directory for your plugins. The plugins directory is the location in your
|
||||
filesystem where Pyrogram will automatically load your update handlers.
|
||||
Defaults to None (plugins disabled).
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
@ -161,7 +169,8 @@ class Client(Methods, BaseClient):
|
||||
last_name: str = None,
|
||||
workers: int = BaseClient.WORKERS,
|
||||
workdir: str = BaseClient.WORKDIR,
|
||||
config_file: str = BaseClient.CONFIG_FILE):
|
||||
config_file: str = BaseClient.CONFIG_FILE,
|
||||
plugins_dir: str = None):
|
||||
super().__init__()
|
||||
|
||||
self.session_name = session_name
|
||||
@ -184,6 +193,7 @@ class Client(Methods, BaseClient):
|
||||
self.workers = workers
|
||||
self.workdir = workdir
|
||||
self.config_file = config_file
|
||||
self.plugins_dir = plugins_dir
|
||||
|
||||
self.dispatcher = Dispatcher(self, workers)
|
||||
|
||||
@ -208,7 +218,8 @@ class Client(Methods, BaseClient):
|
||||
Requires no parameters.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ConnectionError`` in case you try to start an already started Client.
|
||||
"""
|
||||
if self.is_started:
|
||||
raise ConnectionError("Client has already been started")
|
||||
@ -219,6 +230,7 @@ class Client(Methods, BaseClient):
|
||||
|
||||
self.load_config()
|
||||
self.load_session()
|
||||
self.load_plugins()
|
||||
|
||||
self.session = Session(
|
||||
self,
|
||||
@ -285,6 +297,9 @@ class Client(Methods, BaseClient):
|
||||
def stop(self):
|
||||
"""Use this method to manually stop the Client.
|
||||
Requires no parameters.
|
||||
|
||||
Raises:
|
||||
``ConnectionError`` in case you try to stop an already stopped Client.
|
||||
"""
|
||||
if not self.is_started:
|
||||
raise ConnectionError("Client is already stopped")
|
||||
@ -344,7 +359,7 @@ class Client(Methods, BaseClient):
|
||||
Requires no parameters.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.start()
|
||||
self.idle()
|
||||
@ -876,7 +891,7 @@ class Client(Methods, BaseClient):
|
||||
|
||||
Args:
|
||||
data (``Object``):
|
||||
The API Scheme function filled with proper arguments.
|
||||
The API Schema function filled with proper arguments.
|
||||
|
||||
retries (``int``):
|
||||
Number of retries.
|
||||
@ -885,7 +900,7 @@ class Client(Methods, BaseClient):
|
||||
Timeout in seconds.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
if not self.is_started:
|
||||
raise ConnectionError("Client has not been started")
|
||||
@ -968,6 +983,45 @@ class Client(Methods, BaseClient):
|
||||
if peer:
|
||||
self.peers_by_phone[k] = peer
|
||||
|
||||
def load_plugins(self):
|
||||
if self.plugins_dir is not None:
|
||||
plugins_count = 0
|
||||
|
||||
for path in Path(self.plugins_dir).rglob("*.py"):
|
||||
file_path = os.path.splitext(str(path))[0]
|
||||
import_path = []
|
||||
|
||||
while file_path:
|
||||
file_path, tail = os.path.split(file_path)
|
||||
import_path.insert(0, tail)
|
||||
|
||||
import_path = ".".join(import_path)
|
||||
module = import_module(import_path)
|
||||
|
||||
for name in dir(module):
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
handler, group = getattr(module, name)
|
||||
|
||||
if isinstance(handler, Handler) and isinstance(group, int):
|
||||
self.add_handler(handler, group)
|
||||
|
||||
log.info('{}("{}") from "{}" loaded in group {}'.format(
|
||||
type(handler).__name__, name, import_path, group))
|
||||
|
||||
plugins_count += 1
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
if plugins_count > 0:
|
||||
log.warning('Successfully loaded {} plugin{} from "{}"'.format(
|
||||
plugins_count,
|
||||
"s" if plugins_count > 1 else "",
|
||||
self.plugins_dir
|
||||
))
|
||||
else:
|
||||
log.warning('No plugin loaded: "{}" doesn\'t contain any valid plugin'.format(self.plugins_dir))
|
||||
|
||||
def save_session(self):
|
||||
auth_key = base64.b64encode(self.auth_key).decode()
|
||||
auth_key = [auth_key[i: i + 43] for i in range(0, len(auth_key), 43)]
|
||||
@ -1035,7 +1089,8 @@ class Client(Methods, BaseClient):
|
||||
On success, the resolved peer id is returned in form of an InputPeer object.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``KeyError`` in case the peer doesn't exist in the internal database.
|
||||
"""
|
||||
if type(peer_id) is str:
|
||||
if peer_id in ("self", "me"):
|
||||
@ -1075,6 +1130,13 @@ class Client(Methods, BaseClient):
|
||||
progress_args: tuple = ()):
|
||||
part_size = 512 * 1024
|
||||
file_size = os.path.getsize(path)
|
||||
|
||||
if file_size == 0:
|
||||
raise ValueError("File size equals to 0 B")
|
||||
|
||||
if file_size > 1500 * 1024 * 1024:
|
||||
raise ValueError("Telegram doesn't support uploading files bigger than 1500 MiB")
|
||||
|
||||
file_total_parts = int(math.ceil(file_size / part_size))
|
||||
is_big = True if file_size > 10 * 1024 * 1024 else False
|
||||
is_missing_part = True if file_id is not None else False
|
||||
|
@ -25,7 +25,7 @@ from threading import Thread
|
||||
import pyrogram
|
||||
from pyrogram.api import types
|
||||
from ..ext import utils
|
||||
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler
|
||||
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler, DeletedMessagesHandler, UserStatusHandler
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -108,6 +108,8 @@ class Dispatcher:
|
||||
|
||||
callback_query = update.callback_query
|
||||
|
||||
user_status = update.user_status
|
||||
|
||||
if message and isinstance(handler, MessageHandler):
|
||||
if not handler.check(message):
|
||||
continue
|
||||
@ -123,6 +125,11 @@ class Dispatcher:
|
||||
continue
|
||||
|
||||
args = (self.client, callback_query)
|
||||
elif user_status and isinstance(handler, UserStatusHandler):
|
||||
if not handler.check(user_status):
|
||||
continue
|
||||
|
||||
args = (self.client, user_status)
|
||||
else:
|
||||
continue
|
||||
|
||||
@ -209,6 +216,14 @@ class Dispatcher:
|
||||
)
|
||||
)
|
||||
)
|
||||
elif isinstance(update, types.UpdateUserStatus):
|
||||
self.dispatch(
|
||||
pyrogram.Update(
|
||||
user_status=utils.parse_user_status(
|
||||
update.status, update.user_id
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
continue
|
||||
except Exception as e:
|
||||
|
@ -119,7 +119,8 @@ class BaseClient:
|
||||
def get_messages(
|
||||
self,
|
||||
chat_id: int or str,
|
||||
message_ids,
|
||||
message_ids: int or list = None,
|
||||
reply_to_message_ids: int or list = None,
|
||||
replies: int = 1
|
||||
):
|
||||
pass
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -17,15 +17,13 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import logging
|
||||
import time
|
||||
from base64 import b64decode, b64encode
|
||||
from struct import pack
|
||||
from weakref import proxy
|
||||
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from pyrogram.client import types as pyrogram_types
|
||||
from ...api import types, functions
|
||||
from ...api.errors import StickersetInvalid
|
||||
from ...api.errors import StickersetInvalid, MessageIdsEmpty
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
@ -129,6 +127,30 @@ def parse_chat_photo(photo):
|
||||
)
|
||||
|
||||
|
||||
def parse_user_status(user_status, user_id: int = None, is_bot: bool = False) -> pyrogram_types.UserStatus or None:
|
||||
if is_bot:
|
||||
return None
|
||||
|
||||
status = pyrogram_types.UserStatus(user_id)
|
||||
|
||||
if isinstance(user_status, types.UserStatusOnline):
|
||||
status.online = True
|
||||
status.date = user_status.expires
|
||||
elif isinstance(user_status, types.UserStatusOffline):
|
||||
status.offline = True
|
||||
status.date = user_status.was_online
|
||||
elif isinstance(user_status, types.UserStatusRecently):
|
||||
status.recently = True
|
||||
elif isinstance(user_status, types.UserStatusLastWeek):
|
||||
status.within_week = True
|
||||
elif isinstance(user_status, types.UserStatusLastMonth):
|
||||
status.within_month = True
|
||||
else:
|
||||
status.long_time_ago = True
|
||||
|
||||
return status
|
||||
|
||||
|
||||
def parse_user(user: types.User) -> pyrogram_types.User or None:
|
||||
return pyrogram_types.User(
|
||||
id=user.id,
|
||||
@ -142,7 +164,9 @@ def parse_user(user: types.User) -> pyrogram_types.User or None:
|
||||
username=user.username,
|
||||
language_code=user.lang_code,
|
||||
phone_number=user.phone,
|
||||
photo=parse_chat_photo(user.photo)
|
||||
photo=parse_chat_photo(user.photo),
|
||||
status=parse_user_status(user.status, is_bot=user.bot),
|
||||
restriction_reason=user.restriction_reason
|
||||
) if user else None
|
||||
|
||||
|
||||
@ -162,7 +186,8 @@ def parse_user_chat(user: types.User) -> pyrogram_types.Chat:
|
||||
username=user.username,
|
||||
first_name=user.first_name,
|
||||
last_name=user.last_name,
|
||||
photo=parse_chat_photo(user.photo)
|
||||
photo=parse_chat_photo(user.photo),
|
||||
restriction_reason=user.restriction_reason
|
||||
)
|
||||
|
||||
|
||||
@ -187,7 +212,8 @@ def parse_channel_chat(channel: types.Channel) -> pyrogram_types.Chat:
|
||||
type="supergroup" if channel.megagroup else "channel",
|
||||
title=channel.title,
|
||||
username=getattr(channel, "username", None),
|
||||
photo=parse_chat_photo(getattr(channel, "photo", None))
|
||||
photo=parse_chat_photo(getattr(channel, "photo", None)),
|
||||
restriction_reason=getattr(channel, "restriction_reason", None)
|
||||
)
|
||||
|
||||
|
||||
@ -580,6 +606,8 @@ def parse_messages(
|
||||
forward_from_message_id=forward_from_message_id,
|
||||
forward_signature=forward_signature,
|
||||
forward_date=forward_date,
|
||||
mentioned=message.mentioned,
|
||||
media=bool(media) or None,
|
||||
edit_date=message.edit_date,
|
||||
media_group_id=message.grouped_id,
|
||||
photo=photo,
|
||||
@ -607,18 +635,14 @@ def parse_messages(
|
||||
m.caption.init(m._client, m.caption_entities or [])
|
||||
|
||||
if message.reply_to_msg_id and replies:
|
||||
while True:
|
||||
try:
|
||||
m.reply_to_message = client.get_messages(
|
||||
m.chat.id, message.reply_to_msg_id,
|
||||
replies=replies - 1
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("get_messages flood: waiting {} seconds".format(e.x))
|
||||
time.sleep(e.x)
|
||||
continue
|
||||
else:
|
||||
break
|
||||
try:
|
||||
m.reply_to_message = client.get_messages(
|
||||
m.chat.id,
|
||||
reply_to_message_ids=message.id,
|
||||
replies=replies - 1
|
||||
)
|
||||
except MessageIdsEmpty:
|
||||
pass
|
||||
elif isinstance(message, types.MessageService):
|
||||
action = message.action
|
||||
|
||||
@ -705,6 +729,7 @@ def parse_messages(
|
||||
date=message.date,
|
||||
chat=parse_chat(message, users, chats),
|
||||
from_user=parse_user(users.get(message.from_id, None)),
|
||||
service=True,
|
||||
new_chat_members=new_chat_members,
|
||||
left_chat_member=left_chat_member,
|
||||
new_chat_title=new_chat_title,
|
||||
@ -719,20 +744,16 @@ def parse_messages(
|
||||
)
|
||||
|
||||
if isinstance(action, types.MessageActionPinMessage):
|
||||
while True:
|
||||
try:
|
||||
m.pinned_message = client.get_messages(
|
||||
m.chat.id, message.reply_to_msg_id,
|
||||
replies=0
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("get_messages flood: waiting {} seconds".format(e.x))
|
||||
time.sleep(e.x)
|
||||
continue
|
||||
else:
|
||||
break
|
||||
try:
|
||||
m.pinned_message = client.get_messages(
|
||||
m.chat.id,
|
||||
reply_to_message_ids=message.id,
|
||||
replies=0
|
||||
)
|
||||
except MessageIdsEmpty:
|
||||
pass
|
||||
else:
|
||||
m = pyrogram_types.Message(message_id=message.id, client=proxy(client))
|
||||
m = pyrogram_types.Message(message_id=message.id, client=proxy(client), empty=True)
|
||||
|
||||
parsed_messages.append(m)
|
||||
|
||||
@ -934,7 +955,7 @@ def parse_chat_full(
|
||||
if full_chat.pinned_msg_id:
|
||||
parsed_chat.pinned_message = client.get_messages(
|
||||
parsed_chat.id,
|
||||
full_chat.pinned_msg_id
|
||||
message_ids=full_chat.pinned_msg_id
|
||||
)
|
||||
|
||||
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
|
||||
@ -957,6 +978,7 @@ def parse_chat_members(members: types.channels.ChannelParticipants or types.mess
|
||||
parsed_members = []
|
||||
|
||||
if isinstance(members, types.channels.ChannelParticipants):
|
||||
count = members.count
|
||||
members = members.participants
|
||||
|
||||
for member in members:
|
||||
@ -1015,7 +1037,7 @@ def parse_chat_members(members: types.channels.ChannelParticipants or types.mess
|
||||
parsed_members.append(chat_member)
|
||||
|
||||
return pyrogram_types.ChatMembers(
|
||||
total_count=members.count,
|
||||
total_count=count,
|
||||
chat_members=parsed_members
|
||||
)
|
||||
else:
|
||||
|
@ -166,9 +166,41 @@ class Filters:
|
||||
inline_keyboard = create("InlineKeyboard", lambda _, m: isinstance(m.reply_markup, InlineKeyboardMarkup))
|
||||
"""Filter messages containing inline keyboard markups"""
|
||||
|
||||
mentioned = create("Mentioned", lambda _, m: bool(m.mentioned))
|
||||
"""Filter messages containing mentions"""
|
||||
|
||||
service = create("Service", lambda _, m: bool(m.service))
|
||||
"""Filter service messages. A service message contains any of the following fields set
|
||||
|
||||
- left_chat_member
|
||||
- new_chat_title
|
||||
- new_chat_photo
|
||||
- delete_chat_photo
|
||||
- group_chat_created
|
||||
- supergroup_chat_created
|
||||
- channel_chat_created
|
||||
- migrate_to_chat_id
|
||||
- migrate_from_chat_id
|
||||
- pinned_message"""
|
||||
|
||||
media = create("Media", lambda _, m: bool(m.media))
|
||||
"""Filter media messages. A media message contains any of the following fields set
|
||||
|
||||
- audio
|
||||
- document
|
||||
- photo
|
||||
- sticker
|
||||
- video
|
||||
- animation
|
||||
- voice
|
||||
- video_note
|
||||
- contact
|
||||
- location
|
||||
- venue"""
|
||||
|
||||
@staticmethod
|
||||
def command(command: str or list,
|
||||
prefix: str = "/",
|
||||
prefix: str or list = "/",
|
||||
separator: str = " ",
|
||||
case_sensitive: bool = False):
|
||||
"""Filter commands, i.e.: text messages starting with "/" or any other custom prefix.
|
||||
@ -180,9 +212,10 @@ class Filters:
|
||||
a command arrives, the command itself and its arguments will be stored in the *command*
|
||||
field of the :class:`Message <pyrogram.Message>`.
|
||||
|
||||
prefix (``str``, *optional*):
|
||||
The command prefix. Defaults to "/" (slash).
|
||||
Examples: /start, .help, !settings.
|
||||
prefix (``str`` | ``list``, *optional*):
|
||||
A prefix or a list of prefixes as string the filter should look for.
|
||||
Defaults to "/" (slash). Examples: ".", "!", ["/", "!", "."].
|
||||
Can be None or "" (empty string) to allow commands with no prefix at all.
|
||||
|
||||
separator (``str``, *optional*):
|
||||
The command arguments separator. Defaults to " " (white space).
|
||||
@ -194,11 +227,14 @@ class Filters:
|
||||
"""
|
||||
|
||||
def f(_, m):
|
||||
if m.text and m.text.startswith(_.p):
|
||||
t = m.text.split(_.s)
|
||||
c, a = t[0][len(_.p):], t[1:]
|
||||
c = c if _.cs else c.lower()
|
||||
m.command = ([c] + a) if c in _.c else None
|
||||
if m.text:
|
||||
for i in _.p:
|
||||
if m.text.startswith(i):
|
||||
t = m.text.split(_.s)
|
||||
c, a = t[0][len(i):], t[1:]
|
||||
c = c if _.cs else c.lower()
|
||||
m.command = ([c] + a) if c in _.c else None
|
||||
break
|
||||
|
||||
return bool(m.command)
|
||||
|
||||
@ -211,7 +247,7 @@ class Filters:
|
||||
else {c if case_sensitive
|
||||
else c.lower()
|
||||
for c in command},
|
||||
p=prefix,
|
||||
p=set(prefix) if prefix else {""},
|
||||
s=separator,
|
||||
cs=case_sensitive
|
||||
)
|
||||
@ -246,15 +282,16 @@ class Filters:
|
||||
Args:
|
||||
users (``int`` | ``str`` | ``list``):
|
||||
Pass one or more user ids/usernames to filter users.
|
||||
For you yourself, "me" or "self" can be used as well.
|
||||
Defaults to None (no users).
|
||||
"""
|
||||
|
||||
def __init__(self, users: int or str or list = None):
|
||||
users = [] if users is None else users if type(users) is list else [users]
|
||||
super().__init__(
|
||||
{i.lower().strip("@") if type(i) is str else i for i in users}
|
||||
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in users}
|
||||
if type(users) is list else
|
||||
{users.lower().strip("@") if type(users) is str else users}
|
||||
{"me" if users in ["me", "self"] else users.lower().strip("@") if type(users) is str else users}
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
@ -262,7 +299,9 @@ class Filters:
|
||||
message.from_user
|
||||
and (message.from_user.id in self
|
||||
or (message.from_user.username
|
||||
and message.from_user.username.lower() in self))
|
||||
and message.from_user.username.lower() in self)
|
||||
or ("me" in self
|
||||
and message.from_user.is_self))
|
||||
)
|
||||
|
||||
# noinspection PyPep8Naming
|
||||
@ -275,15 +314,16 @@ class Filters:
|
||||
Args:
|
||||
chats (``int`` | ``str`` | ``list``):
|
||||
Pass one or more chat ids/usernames to filter chats.
|
||||
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||
Defaults to None (no chats).
|
||||
"""
|
||||
|
||||
def __init__(self, chats: int or str or list = None):
|
||||
chats = [] if chats is None else chats if type(chats) is list else [chats]
|
||||
super().__init__(
|
||||
{i.lower().strip("@") if type(i) is str else i for i in chats}
|
||||
{"me" if i in ["me", "self"] else i.lower().strip("@") if type(i) is str else i for i in chats}
|
||||
if type(chats) is list else
|
||||
{chats.lower().strip("@") if type(chats) is str else chats}
|
||||
{"me" if chats in ["me", "self"] else chats.lower().strip("@") if type(chats) is str else chats}
|
||||
)
|
||||
|
||||
def __call__(self, message):
|
||||
@ -291,41 +331,10 @@ class Filters:
|
||||
message.chat
|
||||
and (message.chat.id in self
|
||||
or (message.chat.username
|
||||
and message.chat.username.lower() in self))
|
||||
and message.chat.username.lower() in self)
|
||||
or ("me" in self and message.from_user
|
||||
and message.from_user.is_self
|
||||
and not message.outgoing))
|
||||
)
|
||||
|
||||
service = create(
|
||||
"Service",
|
||||
lambda _, m: bool(
|
||||
Filters.new_chat_members(m)
|
||||
or Filters.left_chat_member(m)
|
||||
or Filters.new_chat_title(m)
|
||||
or Filters.new_chat_photo(m)
|
||||
or Filters.delete_chat_photo(m)
|
||||
or Filters.group_chat_created(m)
|
||||
or Filters.supergroup_chat_created(m)
|
||||
or Filters.channel_chat_created(m)
|
||||
or Filters.migrate_to_chat_id(m)
|
||||
or Filters.migrate_from_chat_id(m)
|
||||
or Filters.pinned_message(m)
|
||||
)
|
||||
)
|
||||
"""Filter all service messages."""
|
||||
|
||||
media = create(
|
||||
"Media",
|
||||
lambda _, m: bool(
|
||||
Filters.audio(m)
|
||||
or Filters.document(m)
|
||||
or Filters.photo(m)
|
||||
or Filters.sticker(m)
|
||||
or Filters.video(m)
|
||||
or Filters.animation(m)
|
||||
or Filters.voice(m)
|
||||
or Filters.video_note(m)
|
||||
or Filters.contact(m)
|
||||
or Filters.location(m)
|
||||
or Filters.venue(m)
|
||||
)
|
||||
)
|
||||
"""Filter all media messages."""
|
||||
dan = create("Dan", lambda _, m: bool(m.from_user and m.from_user.id == 23122162))
|
||||
|
@ -17,7 +17,8 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .callback_query_handler import CallbackQueryHandler
|
||||
from .deleted_messages_handler import DeletedMessagesHandler
|
||||
from .disconnect_handler import DisconnectHandler
|
||||
from .message_handler import MessageHandler
|
||||
from .deleted_messages_handler import DeletedMessagesHandler
|
||||
from .raw_update_handler import RawUpdateHandler
|
||||
from .user_status_handler import UserStatusHandler
|
||||
|
54
pyrogram/client/handlers/user_status_handler.py
Normal file
54
pyrogram/client/handlers/user_status_handler.py
Normal file
@ -0,0 +1,54 @@
|
||||
# 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 .handler import Handler
|
||||
|
||||
|
||||
class UserStatusHandler(Handler):
|
||||
"""The UserStatus handler class. Used to handle user status updates (user going online or offline).
|
||||
It is intended to be used with :meth:`add_handler() <pyrogram.Client.add_handler>`
|
||||
|
||||
For a nicer way to register this handler, have a look at the
|
||||
:meth:`on_user_status() <pyrogram.Client.on_user_status>` decorator.
|
||||
|
||||
Args:
|
||||
callback (``callable``):
|
||||
Pass a function that will be called when a new UserStatus update arrives. It takes *(client, user_status)*
|
||||
as positional arguments (look at the section below for a detailed description).
|
||||
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
Pass one or more filters to allow only a subset of messages to be passed
|
||||
in your callback function.
|
||||
|
||||
Other parameters:
|
||||
client (:obj:`Client <pyrogram.Client>`):
|
||||
The Client itself, useful when you want to call other API methods inside the user status handler.
|
||||
|
||||
user_status (:obj:`UserStatus <pyrogram.UserStatus>`):
|
||||
The received UserStatus update.
|
||||
"""
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, user_status):
|
||||
return (
|
||||
self.filters(user_status)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
@ -50,6 +50,12 @@ class AnswerCallbackQuery(BaseClient):
|
||||
cache_time (``int``):
|
||||
The maximum amount of time in seconds that the result of the callback query may be cached client-side.
|
||||
Telegram apps will support caching starting in version 3.14. Defaults to 0.
|
||||
|
||||
Returns:
|
||||
True, on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.SetBotCallbackAnswer(
|
||||
|
@ -54,8 +54,8 @@ class GetInlineBotResults(BaseClient):
|
||||
On Success, :obj:`BotResults <pyrogram.api.types.messages.BotResults>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``TimeoutError``: If the bot fails to answer within 10 seconds
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``TimeoutError`` if the bot fails to answer within 10 seconds
|
||||
"""
|
||||
# TODO: Don't return the raw type
|
||||
|
||||
|
@ -45,8 +45,8 @@ class RequestCallbackAnswer(BaseClient):
|
||||
or as an alert.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``TimeoutError``: If the bot fails to answer within 10 seconds
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``TimeoutError`` if the bot fails to answer within 10 seconds.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.GetBotCallbackAnswer(
|
||||
|
@ -53,7 +53,7 @@ class SendInlineBotResult(BaseClient):
|
||||
On success, the sent Message is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return self.send(
|
||||
functions.messages.SendInlineBotResult(
|
||||
|
@ -38,8 +38,8 @@ class DeleteChatPhoto(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -35,7 +35,7 @@ class ExportChatInviteLink(BaseClient):
|
||||
On success, the exported invite link as string is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -33,7 +33,7 @@ class GetChat(BaseClient):
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -39,7 +39,7 @@ class GetChatMember(BaseClient):
|
||||
On success, a :obj:`ChatMember <pyrogram.ChatMember>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
chat_id = self.resolve_peer(chat_id)
|
||||
user_id = self.resolve_peer(user_id)
|
||||
|
@ -39,7 +39,7 @@ class GetChatMembers(BaseClient):
|
||||
"""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.
|
||||
You must be admin to retrieve the members list of a channel (also known as "subscribers").
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
@ -51,7 +51,7 @@ class GetChatMembers(BaseClient):
|
||||
|
||||
limit (``int``, *optional*):
|
||||
Limits the number of members to be retrieved.
|
||||
Defaults to 200, which is also the maximum limit allowed per method call.
|
||||
Defaults to 200, which is also the maximum server limit allowed per method call.
|
||||
|
||||
query (``str``, *optional*):
|
||||
Query string to filter members based on their display names and usernames.
|
||||
@ -68,9 +68,17 @@ class GetChatMembers(BaseClient):
|
||||
*"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.
|
||||
.. [1] Server limit: on supergroups, you can get up to 10,000 members for a single query and up to 200 members
|
||||
on channels.
|
||||
|
||||
.. [2] A query string is applicable only for *"all"*, *"kicked"* and *"restricted"* filters only.
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`ChatMembers` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if you used an invalid filter or a chat_id that belongs to a user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -32,8 +32,8 @@ class GetChatMembersCount(BaseClient):
|
||||
On success, an integer is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -47,7 +47,7 @@ class GetDialogs(BaseClient):
|
||||
On success, a :obj:`Dialogs` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
if pinned_only:
|
||||
|
@ -30,7 +30,7 @@ class JoinChat(BaseClient):
|
||||
channel/supergroup (in the format @username).
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
match = self.INVITE_LINK_RE.match(chat_id)
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.client.ext import utils
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
@ -52,13 +53,13 @@ class KickChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
chat_peer = self.resolve_peer(chat_id)
|
||||
user_peer = self.resolve_peer(user_id)
|
||||
|
||||
if isinstance(chat_peer, types.InputPeerChannel):
|
||||
self.send(
|
||||
r = self.send(
|
||||
functions.channels.EditBanned(
|
||||
channel=chat_peer,
|
||||
user_id=user_peer,
|
||||
@ -76,11 +77,17 @@ class KickChatMember(BaseClient):
|
||||
)
|
||||
)
|
||||
else:
|
||||
self.send(
|
||||
r = self.send(
|
||||
functions.messages.DeleteChatUser(
|
||||
chat_id=abs(chat_id),
|
||||
user_id=user_peer
|
||||
)
|
||||
)
|
||||
|
||||
return True
|
||||
for i in r.updates:
|
||||
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
|
||||
return utils.parse_messages(
|
||||
self, i.message,
|
||||
{i.id: i for i in r.users},
|
||||
{i.id: i for i in r.chats}
|
||||
)
|
||||
|
@ -33,7 +33,7 @@ class LeaveChat(BaseClient):
|
||||
Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -41,8 +41,8 @@ class PinChatMessage(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -74,7 +74,7 @@ class PromoteChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.channels.EditAdmin(
|
||||
|
@ -64,7 +64,7 @@ class RestrictChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
send_messages = True
|
||||
send_media = True
|
||||
|
@ -36,8 +36,8 @@ class SetChatDescription(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -45,8 +45,8 @@ class SetChatPhoto(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -41,8 +41,8 @@ class SetChatTitle(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id belongs to user.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to user.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -40,7 +40,7 @@ class UnbanChatMember(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
self.send(
|
||||
functions.channels.EditBanned(
|
||||
|
@ -34,8 +34,8 @@ class UnpinChatMessage(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If a chat_id doesn't belong to a supergroup or a channel.
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id doesn't belong to a supergroup or a channel.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
|
@ -32,7 +32,7 @@ class AddContacts(BaseClient):
|
||||
On success, the added contacts are returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
imported_contacts = self.send(
|
||||
functions.contacts.ImportContacts(
|
||||
|
@ -34,7 +34,7 @@ class DeleteContacts(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
contacts = []
|
||||
|
||||
|
@ -36,7 +36,7 @@ class GetContacts(BaseClient):
|
||||
On success, the user's contacts are returned
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
while True:
|
||||
try:
|
||||
|
@ -17,11 +17,19 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from .on_callback_query import OnCallbackQuery
|
||||
from .on_deleted_messages import OnDeletedMessages
|
||||
from .on_disconnect import OnDisconnect
|
||||
from .on_message import OnMessage
|
||||
from .on_deleted_messages import OnDeletedMessages
|
||||
from .on_raw_update import OnRawUpdate
|
||||
from .on_user_status import OnUserStatus
|
||||
|
||||
|
||||
class Decorators(OnMessage, OnDeletedMessages, OnCallbackQuery, OnRawUpdate, OnDisconnect):
|
||||
class Decorators(
|
||||
OnMessage,
|
||||
OnDeletedMessages,
|
||||
OnCallbackQuery,
|
||||
OnRawUpdate,
|
||||
OnDisconnect,
|
||||
OnUserStatus
|
||||
):
|
||||
pass
|
||||
|
@ -17,6 +17,7 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.client.filters.filter import Filter
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
@ -36,7 +37,14 @@ class OnCallbackQuery(BaseClient):
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group)
|
||||
return func
|
||||
handler = pyrogram.CallbackQueryHandler(func, filters)
|
||||
|
||||
if isinstance(self, Filter):
|
||||
return pyrogram.CallbackQueryHandler(func, self), group if filters is None else filters
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
||||
|
@ -17,6 +17,7 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.client.filters.filter import Filter
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
@ -36,7 +37,14 @@ class OnDeletedMessages(BaseClient):
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
self.add_handler(pyrogram.DeletedMessagesHandler(func, filters), group)
|
||||
return func
|
||||
handler = pyrogram.DeletedMessagesHandler(func, filters)
|
||||
|
||||
if isinstance(self, Filter):
|
||||
return pyrogram.DeletedMessagesHandler(func, self), group if filters is None else filters
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
||||
|
@ -28,7 +28,11 @@ class OnDisconnect(BaseClient):
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
self.add_handler(pyrogram.DisconnectHandler(func))
|
||||
return func
|
||||
handler = pyrogram.DisconnectHandler(func)
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler)
|
||||
|
||||
return handler
|
||||
|
||||
return decorator
|
||||
|
@ -17,11 +17,12 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.client.filters.filter import Filter
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnMessage(BaseClient):
|
||||
def on_message(self, filters=None, group: int = 0):
|
||||
def on_message(self=None, filters=None, group: int = 0):
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
messages. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`MessageHandler`.
|
||||
@ -36,7 +37,14 @@ class OnMessage(BaseClient):
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
self.add_handler(pyrogram.MessageHandler(func, filters), group)
|
||||
return func
|
||||
handler = pyrogram.MessageHandler(func, filters)
|
||||
|
||||
if isinstance(self, Filter):
|
||||
return pyrogram.MessageHandler(func, self), group if filters is None else filters
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
||||
|
@ -21,7 +21,7 @@ from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnRawUpdate(BaseClient):
|
||||
def on_raw_update(self, group: int = 0):
|
||||
def on_raw_update(self=None, group: int = 0):
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
raw updates. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`RawUpdateHandler`.
|
||||
@ -32,7 +32,14 @@ class OnRawUpdate(BaseClient):
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
self.add_handler(pyrogram.RawUpdateHandler(func), group)
|
||||
return func
|
||||
handler = pyrogram.RawUpdateHandler(func)
|
||||
|
||||
if isinstance(self, int):
|
||||
return handler, group if self is None else group
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
||||
|
49
pyrogram/client/methods/decorators/on_user_status.py
Normal file
49
pyrogram/client/methods/decorators/on_user_status.py
Normal file
@ -0,0 +1,49 @@
|
||||
# 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 pyrogram
|
||||
from pyrogram.client.filters.filter import Filter
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class OnUserStatus(BaseClient):
|
||||
def on_user_status(self=None, filters=None, group: int = 0):
|
||||
"""Use this decorator to automatically register a function for handling
|
||||
user status updates. This does the same thing as :meth:`add_handler` using the
|
||||
:class:`UserStatusHandler`.
|
||||
|
||||
Args:
|
||||
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||
Pass one or more filters to allow only a subset of UserStatus updated to be passed in your function.
|
||||
|
||||
group (``int``, *optional*):
|
||||
The group identifier, defaults to 0.
|
||||
"""
|
||||
|
||||
def decorator(func):
|
||||
handler = pyrogram.UserStatusHandler(func, filters)
|
||||
|
||||
if isinstance(self, Filter):
|
||||
return pyrogram.UserStatusHandler(func, self), group if filters is None else filters
|
||||
|
||||
if self is not None:
|
||||
self.add_handler(handler, group)
|
||||
|
||||
return handler, group
|
||||
|
||||
return decorator
|
@ -53,7 +53,7 @@ class DeleteMessages(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
peer = self.resolve_peer(chat_id)
|
||||
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
|
||||
|
@ -53,7 +53,7 @@ class EditMessageCaption(BaseClient):
|
||||
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
||||
|
@ -57,6 +57,12 @@ class EditMessageMedia(BaseClient):
|
||||
|
||||
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
|
||||
An InlineKeyboardMarkup object.
|
||||
|
||||
Returns:
|
||||
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
style = self.html if media.parse_mode.lower() == "html" else self.markdown
|
||||
caption = media.caption
|
||||
|
@ -44,7 +44,7 @@ class EditMessageReplyMarkup(BaseClient):
|
||||
:obj:`Message <pyrogram.Message>` is returned, otherwise True is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
r = self.send(
|
||||
|
@ -57,7 +57,7 @@ class EditMessageText(BaseClient):
|
||||
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
||||
|
@ -54,7 +54,7 @@ class ForwardMessages(BaseClient):
|
||||
is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
is_iterable = not isinstance(message_ids, int)
|
||||
message_ids = list(message_ids) if is_iterable else [message_ids]
|
||||
|
@ -56,7 +56,7 @@ class GetHistory(BaseClient):
|
||||
On success, a :obj:`Messages <pyrogram.Messages>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
r = self.send(
|
||||
|
@ -23,9 +23,10 @@ from ...ext import BaseClient, utils
|
||||
class GetMessages(BaseClient):
|
||||
def get_messages(self,
|
||||
chat_id: int or str,
|
||||
message_ids,
|
||||
message_ids: int or list = None,
|
||||
reply_to_message_ids: int or list = None,
|
||||
replies: int = 1):
|
||||
"""Use this method to get messages that belong to a specific chat.
|
||||
"""Use this method to get one or more messages that belong to a specific chat.
|
||||
You can retrieve up to 200 messages at once.
|
||||
|
||||
Args:
|
||||
@ -34,36 +35,46 @@ class GetMessages(BaseClient):
|
||||
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).
|
||||
|
||||
message_ids (``iterable``):
|
||||
A list of Message identifiers in the chat specified in *chat_id* or a single message id, as integer.
|
||||
Iterators and Generators are also accepted.
|
||||
message_ids (``iterable``, *optional*):
|
||||
Pass a single message identifier or a list of message ids (as integers) to get the content of the
|
||||
message themselves. Iterators and Generators are also accepted.
|
||||
|
||||
reply_to_message_ids (``iterable``, *optional*):
|
||||
Pass a single message identifier or a list of message ids (as integers) to get the content of
|
||||
the previous message you replied to using this message. Iterators and Generators are also accepted.
|
||||
If *message_ids* is set, this argument will be ignored.
|
||||
|
||||
replies (``int``, *optional*):
|
||||
The number of subsequent replies to get for each message. Defaults to 1.
|
||||
|
||||
Returns:
|
||||
On success and in case *message_ids* was a list, the returned value will be a list of the requested
|
||||
:obj:`Messages <pyrogram.Messages>` even if a list contains just one element, otherwise if
|
||||
*message_ids* was an integer, the single requested :obj:`Message <pyrogram.Message>`
|
||||
is returned.
|
||||
On success and in case *message_ids* or *reply_to_message_ids* was a list, the returned value will be a
|
||||
list of the requested :obj:`Messages <pyrogram.Messages>` even if a list contains just one element,
|
||||
otherwise if *message_ids* or *reply_to_message_ids* was an integer, the single requested
|
||||
:obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
ids, ids_type = (
|
||||
(message_ids, types.InputMessageID) if message_ids
|
||||
else (reply_to_message_ids, types.InputMessageReplyTo) if reply_to_message_ids
|
||||
else (None, None)
|
||||
)
|
||||
|
||||
if ids is None:
|
||||
raise ValueError("No argument supplied")
|
||||
|
||||
peer = self.resolve_peer(chat_id)
|
||||
is_iterable = not isinstance(message_ids, int)
|
||||
message_ids = list(message_ids) if is_iterable else [message_ids]
|
||||
message_ids = [types.InputMessageID(i) for i in message_ids]
|
||||
|
||||
is_iterable = not isinstance(ids, int)
|
||||
ids = list(ids) if is_iterable else [ids]
|
||||
ids = [ids_type(i) for i in ids]
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
rpc = functions.channels.GetMessages(
|
||||
channel=peer,
|
||||
id=message_ids
|
||||
)
|
||||
rpc = functions.channels.GetMessages(channel=peer, id=ids)
|
||||
else:
|
||||
rpc = functions.messages.GetMessages(
|
||||
id=message_ids
|
||||
)
|
||||
rpc = functions.messages.GetMessages(id=ids)
|
||||
|
||||
r = self.send(rpc)
|
||||
|
||||
|
@ -56,7 +56,7 @@ class SendAnimation(BaseClient):
|
||||
pass a file path as string to upload a new animation that exists on your local machine.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Animation caption, 0-200 characters.
|
||||
Animation caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -116,7 +116,7 @@ class SendAnimation(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -58,7 +58,7 @@ class SendAudio(BaseClient):
|
||||
pass a file path as string to upload a new audio file that exists on your local machine.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Audio caption, 0-200 characters.
|
||||
Audio caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -118,7 +118,7 @@ class SendAudio(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -47,8 +47,8 @@ class SendChatAction(BaseClient):
|
||||
On success, True is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If the provided string is not a valid ChatAction
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if the provided string is not a valid ChatAction.
|
||||
"""
|
||||
|
||||
# Resolve Enum type
|
||||
|
@ -65,7 +65,7 @@ class SendContact(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(
|
||||
functions.messages.SendMedia(
|
||||
|
@ -59,7 +59,7 @@ class SendDocument(BaseClient):
|
||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Document caption, 0-200 characters.
|
||||
Document caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -104,7 +104,7 @@ class SendDocument(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -57,7 +57,7 @@ class SendLocation(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(
|
||||
functions.messages.SendMedia(
|
||||
|
@ -64,7 +64,7 @@ class SendMessage(BaseClient):
|
||||
On success, the sent :obj:`Message` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
||||
|
@ -52,7 +52,7 @@ class SendPhoto(BaseClient):
|
||||
pass a file path as string to upload a new photo that exists on your local machine.
|
||||
|
||||
caption (``bool``, *optional*):
|
||||
Photo caption, 0-200 characters.
|
||||
Photo caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -102,7 +102,7 @@ class SendPhoto(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -86,7 +86,7 @@ class SendSticker(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
|
||||
|
@ -74,7 +74,7 @@ class SendVenue(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(
|
||||
functions.messages.SendMedia(
|
||||
|
@ -57,7 +57,7 @@ class SendVideo(BaseClient):
|
||||
pass a file path as string to upload a new video that exists on your local machine.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Video caption, 0-200 characters.
|
||||
Video caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -120,7 +120,7 @@ class SendVideo(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -102,7 +102,7 @@ class SendVideoNote(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
|
||||
|
@ -53,7 +53,7 @@ class SendVoice(BaseClient):
|
||||
pass a file path as string to upload a new audio that exists on your local machine.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Voice message caption, 0-200 characters.
|
||||
Voice message caption, 0-1024 characters.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
@ -101,7 +101,7 @@ class SendVoice(BaseClient):
|
||||
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
file = None
|
||||
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||
|
@ -41,7 +41,7 @@ class ChangeCloudPassword(BaseClient):
|
||||
True on success, False otherwise.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(functions.account.GetPassword())
|
||||
|
||||
|
@ -43,7 +43,7 @@ class EnableCloudPassword(BaseClient):
|
||||
True on success, False otherwise.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(functions.account.GetPassword())
|
||||
|
||||
|
@ -34,7 +34,7 @@ class RemoveCloudPassword(BaseClient):
|
||||
True on success, False otherwise.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
r = self.send(functions.account.GetPassword())
|
||||
|
||||
|
@ -16,15 +16,17 @@
|
||||
# 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 .delete_profile_photos import DeleteProfilePhotos
|
||||
from .delete_user_profile_photos import DeleteUserProfilePhotos
|
||||
from .get_me import GetMe
|
||||
from .get_user_profile_photos import GetUserProfilePhotos
|
||||
from .get_users import GetUsers
|
||||
from .set_user_profile_photo import SetUserProfilePhoto
|
||||
|
||||
|
||||
class Users(
|
||||
GetUserProfilePhotos,
|
||||
DeleteProfilePhotos,
|
||||
SetUserProfilePhoto,
|
||||
DeleteUserProfilePhotos,
|
||||
GetUsers,
|
||||
GetMe
|
||||
):
|
||||
|
@ -23,8 +23,8 @@ from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class DeleteProfilePhotos(BaseClient):
|
||||
def delete_profile_photos(self, id: str or list):
|
||||
class DeleteUserProfilePhotos(BaseClient):
|
||||
def delete_user_profile_photos(self, id: str or list):
|
||||
"""Use this method to delete your own profile photos
|
||||
|
||||
Args:
|
||||
@ -36,7 +36,7 @@ class DeleteProfilePhotos(BaseClient):
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
id = id if isinstance(id, list) else [id]
|
||||
input_photos = []
|
@ -28,7 +28,7 @@ class GetMe(BaseClient):
|
||||
Basic information about the user or bot in form of a :obj:`User` object
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return utils.parse_user(
|
||||
self.send(
|
||||
|
@ -45,7 +45,7 @@ class GetUserProfilePhotos(BaseClient):
|
||||
On success, a :obj:`UserProfilePhotos` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return utils.parse_profile_photos(
|
||||
self.send(
|
||||
|
@ -37,7 +37,7 @@ class GetUsers(BaseClient):
|
||||
*user_ids* was an integer, the single requested :obj:`User` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
is_iterable = not isinstance(user_ids, (int, str))
|
||||
user_ids = list(user_ids) if is_iterable else [user_ids]
|
||||
|
48
pyrogram/client/methods/users/set_user_profile_photo.py
Normal file
48
pyrogram/client/methods/users/set_user_profile_photo.py
Normal file
@ -0,0 +1,48 @@
|
||||
# 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
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class SetUserProfilePhoto(BaseClient):
|
||||
def set_user_profile_photo(self, photo: str):
|
||||
"""Use this method to set a new profile photo.
|
||||
|
||||
This method only works for Users.
|
||||
Bots profile photos must be set using BotFather.
|
||||
|
||||
Args:
|
||||
photo (``str``):
|
||||
Profile photo to set.
|
||||
Pass a file path as string to upload a new photo that exists on your local machine.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
return bool(
|
||||
self.send(
|
||||
functions.photos.UploadProfilePhoto(
|
||||
self.save_file(photo)
|
||||
)
|
||||
)
|
||||
)
|
@ -73,8 +73,8 @@ class DownloadMedia(BaseClient):
|
||||
On success, the absolute path of the downloaded file as string is returned, None otherwise.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>`
|
||||
``ValueError``: If the message doesn't contain any downloadable media
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if the message doesn't contain any downloadable media
|
||||
"""
|
||||
error_message = "This message doesn't contain any downloadable media"
|
||||
|
||||
|
@ -37,5 +37,5 @@ from .messages_and_media import (
|
||||
from .update import Update
|
||||
from .user_and_chats import (
|
||||
Chat, ChatMember, ChatMembers, ChatPhoto,
|
||||
Dialog, Dialogs, User
|
||||
Dialog, Dialogs, User, UserStatus
|
||||
)
|
||||
|
@ -73,7 +73,9 @@ class CallbackQuery(Object):
|
||||
self.game_short_name = game_short_name # flags.3?string
|
||||
|
||||
def answer(self, text: str = None, show_alert: bool = None, url: str = None, cache_time: int = 0):
|
||||
"""Use this method as a shortcut for:
|
||||
"""Bound method *answer* of :obj:`CallbackQuery <pyrogram.CallbackQuery>`.
|
||||
|
||||
Use this method as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -31,7 +31,7 @@ class InlineKeyboardButton(Object):
|
||||
text (``str``):
|
||||
Label text on the button.
|
||||
|
||||
callback_data (``str``, *optional*):
|
||||
callback_data (``bytes``, *optional*):
|
||||
Data to be sent in a callback query to the bot when button is pressed, 1-64 bytes.
|
||||
|
||||
url (``str``, *optional*):
|
||||
@ -50,35 +50,29 @@ class InlineKeyboardButton(Object):
|
||||
chat's input field. Can be empty, in which case only the bot's username will be inserted.This offers a
|
||||
quick way for the user to open your bot in inline mode in the same chat – good for selecting something
|
||||
from multiple options.
|
||||
|
||||
callback_game (:obj:`CallbackGame <pyrogram.CallbackGame>`, *optional*):
|
||||
Description of the game that will be launched when the user presses the button.NOTE: This type of button
|
||||
must always be the first button in the first row.
|
||||
|
||||
pay (``bool``, *optional*):
|
||||
Specify True, to send a Pay button.NOTE: This type of button must always be the first button in the
|
||||
first row.
|
||||
"""
|
||||
|
||||
# TODO: Add callback_game and pay fields
|
||||
|
||||
ID = 0xb0700019
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
text: str,
|
||||
callback_data: str = None,
|
||||
callback_data: bytes = None,
|
||||
url: str = None,
|
||||
switch_inline_query: str = None,
|
||||
switch_inline_query_current_chat: str = None,
|
||||
callback_game=None,
|
||||
pay: bool = None
|
||||
# callback_game=None,
|
||||
# pay: bool = None
|
||||
):
|
||||
self.text = text
|
||||
self.url = url
|
||||
self.callback_data = callback_data
|
||||
self.switch_inline_query = switch_inline_query
|
||||
self.switch_inline_query_current_chat = switch_inline_query_current_chat
|
||||
self.callback_game = callback_game
|
||||
self.pay = pay
|
||||
# self.callback_game = callback_game
|
||||
# self.pay = pay
|
||||
|
||||
@staticmethod
|
||||
def read(b, *args):
|
||||
@ -91,7 +85,7 @@ class InlineKeyboardButton(Object):
|
||||
if isinstance(b, KeyboardButtonCallback):
|
||||
return InlineKeyboardButton(
|
||||
text=b.text,
|
||||
callback_data=b.data.decode()
|
||||
callback_data=b.data
|
||||
)
|
||||
|
||||
if isinstance(b, KeyboardButtonSwitchInline):
|
||||
@ -108,7 +102,7 @@ class InlineKeyboardButton(Object):
|
||||
|
||||
def write(self):
|
||||
if self.callback_data:
|
||||
return KeyboardButtonCallback(self.text, self.callback_data.encode())
|
||||
return KeyboardButtonCallback(self.text, self.callback_data)
|
||||
|
||||
if self.url:
|
||||
return KeyboardButtonUrl(self.text, self.url)
|
||||
|
@ -27,7 +27,7 @@ class InlineKeyboardMarkup(Object):
|
||||
|
||||
Args:
|
||||
inline_keyboard (List of List of :obj:`InlineKeyboardButton <pyrogram.InlineKeyboardButton>`):
|
||||
Array of button rows, each represented by an Array of InlineKeyboardButton objects.
|
||||
List of button rows, each represented by a List of InlineKeyboardButton objects.
|
||||
"""
|
||||
|
||||
ID = 0xb0700020
|
||||
|
@ -25,11 +25,11 @@ from . import KeyboardButton
|
||||
|
||||
|
||||
class ReplyKeyboardMarkup(Object):
|
||||
"""This object represents a custom keyboard with reply options (see Introduction to bots for details and examples).
|
||||
"""This object represents a custom keyboard with reply options.
|
||||
|
||||
Args:
|
||||
keyboard (List of List of :obj:`KeyboardButton <pyrogram.KeyboardButton>`):
|
||||
Array of button rows, each represented by an Array of KeyboardButton objects.
|
||||
List of button rows, each represented by a List of KeyboardButton objects.
|
||||
|
||||
resize_keyboard (``bool``, *optional*):
|
||||
Requests clients to resize the keyboard vertically for optimal fit (e.g., make the keyboard smaller if
|
||||
|
@ -35,7 +35,7 @@ class InputMediaAnimation(InputMedia):
|
||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption of the animation to be sent, 0-200 characters
|
||||
Caption of the animation to be sent, 0-1024 characters
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
|
@ -36,7 +36,7 @@ class InputMediaAudio(InputMedia):
|
||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption of the audio to be sent, 0-200 characters
|
||||
Caption of the audio to be sent, 0-1024 characters
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
|
@ -35,7 +35,7 @@ class InputMediaDocument(InputMedia):
|
||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption of the document to be sent, 0-200 characters
|
||||
Caption of the document to be sent, 0-1024 characters
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
|
@ -31,7 +31,7 @@ class InputMediaPhoto(InputMedia):
|
||||
Sending photo by a URL is currently unsupported.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption of the photo to be sent, 0-200 characters
|
||||
Caption of the photo to be sent, 0-1024 characters
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
|
@ -37,7 +37,7 @@ class InputMediaVideo(InputMedia):
|
||||
Thumbnails can't be reused and can be only uploaded as a new file.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption of the video to be sent, 0-200 characters
|
||||
Caption of the video to be sent, 0-1024 characters
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
|
@ -48,7 +48,7 @@ class Animation(Object):
|
||||
File size.
|
||||
|
||||
date (``int``, *optional*):
|
||||
Date the Animation was sent in Unix time.
|
||||
Date the animation was sent in Unix time.
|
||||
"""
|
||||
|
||||
ID = 0xb0700025
|
||||
|
@ -36,7 +36,7 @@ class Contact(Object):
|
||||
Contact's user identifier in Telegram.
|
||||
|
||||
vcard (``str``, *optional*):
|
||||
Additional data about the contact in the form of a vCard
|
||||
Additional data about the contact in the form of a vCard.
|
||||
"""
|
||||
|
||||
ID = 0xb0700011
|
||||
|
@ -55,6 +55,24 @@ class Message(Object):
|
||||
For replies, the original message. Note that the Message object in this field will not contain
|
||||
further reply_to_message fields even if it itself is a reply.
|
||||
|
||||
mentioned (``bool``, *optional*):
|
||||
The message contains a mention.
|
||||
|
||||
empty (``bool``, *optional*):
|
||||
The message is empty.
|
||||
A message can be empty in case it was deleted or you tried to retrieve a message that doesn't exist yet.
|
||||
|
||||
service (``bool``, *optional*):
|
||||
The message is a service message.
|
||||
A service message has one and only one of these fields set: left_chat_member, new_chat_title,
|
||||
new_chat_photo, delete_chat_photo, group_chat_created, supergroup_chat_created, channel_chat_created,
|
||||
migrate_to_chat_id, migrate_from_chat_id, pinned_message.
|
||||
|
||||
media (``bool``` *optional*):
|
||||
The message is a media message.
|
||||
A media message has one and only one of these fields set: audio, document, photo, sticker, video, animation,
|
||||
voice, video_note, contact, location, venue.
|
||||
|
||||
edit_date (``int``, *optional*):
|
||||
Date the message was last edited in Unix time.
|
||||
|
||||
@ -83,9 +101,6 @@ class Message(Object):
|
||||
document (:obj:`Document <pyrogram.Document>`, *optional*):
|
||||
Message is a general file, information about the file.
|
||||
|
||||
game (:obj:`Game <pyrogram.Game>`, *optional*):
|
||||
Message is a game, information about the game. More about games.
|
||||
|
||||
photo (:obj:`Photo <pyrogram.Photo>`, *optional*):
|
||||
Message is a photo, information about the photo.
|
||||
|
||||
@ -105,7 +120,7 @@ class Message(Object):
|
||||
Message is a video note, information about the video message.
|
||||
|
||||
caption (``str``, *optional*):
|
||||
Caption for the audio, document, photo, video or voice, 0-200 characters.
|
||||
Caption for the audio, document, photo, video or voice, 0-1024 characters.
|
||||
If the message contains caption entities (bold, italic, ...) you can access *caption.markdown* or
|
||||
*caption.html* to get the marked up caption text. In case there is no caption entity, the fields
|
||||
will contain the same text as *caption*.
|
||||
@ -167,20 +182,11 @@ class Message(Object):
|
||||
Note that the Message object in this field will not contain further reply_to_message fields even if it
|
||||
is itself a reply.
|
||||
|
||||
invoice (:obj:`Invoice <pyrogram.Invoice>`, *optional*):
|
||||
Message is an invoice for a payment, information about the invoice. More about payments.
|
||||
|
||||
successful_payment (:obj:`SuccessfulPayment <pyrogram.SuccessfulPayment>`, *optional*):
|
||||
Message is a service message about a successful payment, information about the payment. More about payments.
|
||||
|
||||
connected_website (``str``, *optional*):
|
||||
The domain name of the website on which the user has logged in. More about Telegram Login.
|
||||
|
||||
views (``int``, *optional*):
|
||||
Channel post views.
|
||||
|
||||
via_bot (:obj:`User <pyrogram.User>`):
|
||||
Via bot.
|
||||
The information of the bot that generated the message from an inline query of a user.
|
||||
|
||||
outgoing (``bool``, *optional*):
|
||||
Whether the message is incoming or outgoing.
|
||||
@ -202,6 +208,7 @@ class Message(Object):
|
||||
instructions to remove reply keyboard or to force a reply from the user.
|
||||
"""
|
||||
|
||||
# TODO: Add game missing field. Also invoice, successful_payment, connected_website
|
||||
ID = 0xb0700003
|
||||
|
||||
def __init__(
|
||||
@ -217,6 +224,10 @@ class Message(Object):
|
||||
forward_signature: str = None,
|
||||
forward_date: int = None,
|
||||
reply_to_message=None,
|
||||
mentioned=None,
|
||||
empty=None,
|
||||
service=None,
|
||||
media=None,
|
||||
edit_date: int = None,
|
||||
media_group_id: str = None,
|
||||
author_signature: str = None,
|
||||
@ -225,7 +236,6 @@ class Message(Object):
|
||||
caption_entities: list = None,
|
||||
audio=None,
|
||||
document=None,
|
||||
game=None,
|
||||
photo=None,
|
||||
sticker=None,
|
||||
animation=None,
|
||||
@ -247,9 +257,6 @@ class Message(Object):
|
||||
migrate_to_chat_id: int = None,
|
||||
migrate_from_chat_id: int = None,
|
||||
pinned_message=None,
|
||||
invoice=None,
|
||||
successful_payment=None,
|
||||
connected_website=None,
|
||||
views: int = None,
|
||||
via_bot=None,
|
||||
outgoing: bool = None,
|
||||
@ -268,6 +275,10 @@ class Message(Object):
|
||||
self.forward_signature = forward_signature # flags.4?string
|
||||
self.forward_date = forward_date # flags.5?int
|
||||
self.reply_to_message = reply_to_message # flags.6?Message
|
||||
self.mentioned = mentioned
|
||||
self.empty = empty
|
||||
self.service = service
|
||||
self.media = media
|
||||
self.edit_date = edit_date # flags.7?int
|
||||
self.media_group_id = media_group_id # flags.8?string
|
||||
self.author_signature = author_signature # flags.9?string
|
||||
@ -276,7 +287,6 @@ class Message(Object):
|
||||
self.caption_entities = caption_entities # flags.12?Vector<MessageEntity>
|
||||
self.audio = audio # flags.13?Audio
|
||||
self.document = document # flags.14?Document
|
||||
self.game = game # flags.15?Game
|
||||
self.photo = photo # flags.16?Vector<PhotoSize>
|
||||
self.sticker = sticker # flags.17?Sticker
|
||||
self.animation = animation
|
||||
@ -298,9 +308,6 @@ class Message(Object):
|
||||
self.migrate_to_chat_id = migrate_to_chat_id # flags.33?int
|
||||
self.migrate_from_chat_id = migrate_from_chat_id # flags.34?int
|
||||
self.pinned_message = pinned_message # flags.35?Message
|
||||
self.invoice = invoice # flags.36?Invoice
|
||||
self.successful_payment = successful_payment # flags.37?SuccessfulPayment
|
||||
self.connected_website = connected_website # flags.38?string
|
||||
self.views = views # flags.39?int
|
||||
self.via_bot = via_bot # flags.40?User
|
||||
self.outgoing = outgoing
|
||||
@ -316,7 +323,9 @@ class Message(Object):
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None,
|
||||
reply_markup=None):
|
||||
"""Use this method as a shortcut for:
|
||||
"""Bound method *reply* of :obj:`Message <pyrogram.Message>`.
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -381,10 +390,60 @@ class Message(Object):
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
|
||||
def edit(self, text: str, parse_mode: str = "", disable_web_page_preview: bool = None, reply_markup=None):
|
||||
"""Bound method *edit* of :obj:`Message <pyrogram.Message>
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
client.edit_message_text(
|
||||
chat_id=message.chat.id,
|
||||
message_id=message.message_id,
|
||||
text="hello",
|
||||
)
|
||||
|
||||
Example:
|
||||
.. code-block:: python
|
||||
|
||||
message.edit("hello")
|
||||
|
||||
Args:
|
||||
text (``str``):
|
||||
New text of the message.
|
||||
|
||||
parse_mode (``str``, *optional*):
|
||||
Use :obj:`MARKDOWN <pyrogram.ParseMode.MARKDOWN>` or :obj:`HTML <pyrogram.ParseMode.HTML>`
|
||||
if you want Telegram apps to show bold, italic, fixed-width text or inline URLs in your message.
|
||||
Defaults to Markdown.
|
||||
|
||||
disable_web_page_preview (``bool``, *optional*):
|
||||
Disables link previews for links in this message.
|
||||
|
||||
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
|
||||
An InlineKeyboardMarkup object.
|
||||
|
||||
Returns:
|
||||
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
return self._client.edit_message_text(
|
||||
chat_id=self.chat.id,
|
||||
message_id=self.message_id,
|
||||
text=text,
|
||||
parse_mode=parse_mode,
|
||||
disable_web_page_preview=disable_web_page_preview,
|
||||
reply_markup=reply_markup
|
||||
)
|
||||
|
||||
def forward(self,
|
||||
chat_id: int or str,
|
||||
disable_notification: bool = None):
|
||||
"""Use this method as a shortcut for:
|
||||
"""Bound method *forward* of :obj:`Message <pyrogram.Message>`.
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -423,7 +482,9 @@ class Message(Object):
|
||||
)
|
||||
|
||||
def delete(self, revoke: bool = True):
|
||||
"""Use this method as a shortcut for:
|
||||
"""Bound method *delete* of :obj:`Message <pyrogram.Message>`.
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -459,8 +520,9 @@ class Message(Object):
|
||||
return True
|
||||
|
||||
def click(self, x: int or str, y: int = None, quote: bool = None):
|
||||
"""Use this method to click a button attached to the message.
|
||||
It's a shortcut for:
|
||||
"""Bound method *click* of :obj:`Message <pyrogram.Message>`.
|
||||
|
||||
Use as a shortcut for clicking a button attached to the message instead of.
|
||||
|
||||
- Clicking inline buttons:
|
||||
|
||||
@ -481,16 +543,17 @@ class Message(Object):
|
||||
text=message.reply_markup[i][j].text
|
||||
)
|
||||
|
||||
This method can be used in three different ways:
|
||||
Example:
|
||||
This method can be used in three different ways:
|
||||
|
||||
1. Pass one integer argument only (e.g.: ``.click(2)``, to click a button at index 2).
|
||||
Buttons are counted left to right, starting from the top.
|
||||
1. Pass one integer argument only (e.g.: ``.click(2)``, to click a button at index 2).
|
||||
Buttons are counted left to right, starting from the top.
|
||||
|
||||
2. Pass two integer arguments (e.g.: ``.click(1, 0)``, to click a button at position (1, 0)).
|
||||
The origin (0, 0) is top-left.
|
||||
2. Pass two integer arguments (e.g.: ``.click(1, 0)``, to click a button at position (1, 0)).
|
||||
The origin (0, 0) is top-left.
|
||||
|
||||
3. Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
|
||||
Only the first matching button will be pressed.
|
||||
3. Pass one string argument only (e.g.: ``.click("Settings")``, to click a button by using its label).
|
||||
Only the first matching button will be pressed.
|
||||
|
||||
Args:
|
||||
x (``int`` | ``str``):
|
||||
@ -571,8 +634,10 @@ class Message(Object):
|
||||
else:
|
||||
raise ValueError("The message doesn't contain any keyboard")
|
||||
|
||||
def download(self, file_name: str = "", block: bool = True):
|
||||
"""Use this method as a shortcut for:
|
||||
def download(self, file_name: str = "", block: bool = True, progress: callable = None, progress_args: tuple = None):
|
||||
"""Bound method *download* of :obj:`Message <pyrogram.Message>`.
|
||||
|
||||
Use as a shortcut for:
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
@ -594,6 +659,15 @@ class Message(Object):
|
||||
Blocks the code execution until the file has been downloaded.
|
||||
Defaults to True.
|
||||
|
||||
progress (``callable``):
|
||||
Pass a callback function to view the download progress.
|
||||
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||
below for a detailed description).
|
||||
|
||||
progress_args (``tuple``):
|
||||
Extra custom arguments for the progress callback function. Useful, for example, if you want to pass
|
||||
a chat_id and a message_id in order to edit a message with the updated progress.
|
||||
|
||||
Returns:
|
||||
On success, the absolute path of the downloaded file as string is returned, None otherwise.
|
||||
|
||||
@ -604,5 +678,7 @@ class Message(Object):
|
||||
return self._client.download_media(
|
||||
message=self,
|
||||
file_name=file_name,
|
||||
block=block
|
||||
block=block,
|
||||
progress=progress,
|
||||
progress_args=progress_args,
|
||||
)
|
||||
|
@ -20,7 +20,7 @@ from pyrogram.api.core import Object
|
||||
|
||||
|
||||
class Photo(Object):
|
||||
"""This object represents a Photo
|
||||
"""This object represents a Photo.
|
||||
|
||||
Args:
|
||||
id (``str``):
|
||||
|
@ -52,11 +52,9 @@ class Sticker(Object):
|
||||
|
||||
set_name (``str``, *optional*):
|
||||
Name of the sticker set to which the sticker belongs.
|
||||
|
||||
mask_position (:obj:`MaskPosition <pyrogram.MaskPosition>`, *optional*):
|
||||
For mask stickers, the position where the mask should be placed.
|
||||
"""
|
||||
|
||||
# TODO: Add mask position
|
||||
ID = 0xb0700017
|
||||
|
||||
def __init__(
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user