Merge branch 'develop' into asyncio

This commit is contained in:
Dan 2019-01-07 10:36:52 +01:00
commit 2055736661
19 changed files with 147 additions and 241 deletions

View File

@ -2,21 +2,21 @@
This folder contains example scripts to show you how **Pyrogram** looks like. This folder contains example scripts to show you how **Pyrogram** looks like.
Every script is working right away (provided you correctly set up your credentials), meaning Every script is working right away (provided you correctly set up your credentials), meaning you can simply copy-paste
you can simply copy-paste and run. The only things you have to change are session names and target chats. and run. The only things you have to change are session names and target chats.
All the examples listed in this directory are licensed under the terms of the [CC0 1.0 Universal](LICENSE) license and All the examples listed in this directory are licensed under the terms of the [CC0 1.0 Universal](LICENSE) license and
can be freely used as basic building blocks for your own applications without worrying about copyrights. can be freely used as basic building blocks for your own applications without worrying about copyrights.
Example | Description Example | Description
---: | :--- ---: | :---
[**hello_world**](hello_world.py) | Demonstration of basic API usages [**hello**](hello.py) | Demonstration of basic API usage
[**echo_bot**](echo_bot.py) | Echo bot that replies to every private text message [**echo**](echo.py) | Reply to every private text message
[**welcome_bot**](welcome_bot.py) | The Welcome Bot source code in [@PyrogramChat](https://t.me/pyrogramchat) [**welcome**](welcome.py) | The Welcome Bot in [@PyrogramChat](https://t.me/pyrogramchat)
[**get_history**](get_history.py) | How to retrieve the full message history of a chat [**history**](history.py) | Get the full message history of a chat
[**get_chat_members**](get_chat_members.py) | How to get the first 10.000 members of a supergroup/channel [**chat_members**](chat_members.py) | Get all the members of a chat
[**get_chat_members2**](get_chat_members2.py) | Improved version to get more than 10.000 members [**dialogs**](dialogs.py) | Get all of your dialog chats
[**query_inline_bots**](query_inline_bots.py) | How to query an inline bot and send a result to a chat [**inline_bots**](inline_bots.py) | Query an inline bot and send a result to a chat
[**send_bot_keyboards**](send_bot_keyboards.py) | How to send normal and inline keyboards using regular bots [**keyboards**](keyboards.py) | Send normal and inline keyboards using regular bots
[**callback_query_handler**](callback_query_handler.py) | How to handle queries coming from inline button presses [**callback_queries**](callback_queries.py) | Handle queries coming from inline button presses
[**raw_update_handler**](raw_update_handler.py) | How to handle raw updates (old, should be avoided) [**raw_updates**](raw_updates.py) | Handle raw updates (old, should be avoided)

10
examples/chat_members.py Normal file
View File

@ -0,0 +1,10 @@
"""This example shows how to get all the members of a chat."""
from pyrogram import Client
app = Client("my_count")
target = "pyrogramchat" # Target channel/supergroup
with app:
for member in app.iter_chat_members(target):
print(member.user.first_name)

9
examples/dialogs.py Normal file
View File

@ -0,0 +1,9 @@
"""This example shows how to get the full dialogs list of a user."""
from pyrogram import Client
app = Client("my_account")
with app:
for dialog in app.iter_dialogs():
print(dialog.chat.title or dialog.chat.first_name)

View File

@ -11,7 +11,7 @@ app = Client("my_account")
@app.on_message(Filters.text & Filters.private) @app.on_message(Filters.text & Filters.private)
def echo(client, message): def echo(client, message):
message.reply(message.text, quote=True) message.reply(message.text)
app.run() # Automatically start() and idle() app.run() # Automatically start() and idle()

View File

@ -1,31 +0,0 @@
"""This example shows you how to get the first 10.000 members of a chat.
Refer to get_chat_members2.py for more than 10.000 members.
"""
import time
from pyrogram import Client
from pyrogram.api.errors import FloodWait
app = Client("my_account")
target = "pyrogramchat" # Target channel/supergroup
members = [] # List that will contain all the members of the target chat
offset = 0 # Offset starts at 0
limit = 200 # Amount of users to retrieve for each API call (max 200)
with app:
while True:
try:
chunk = app.get_chat_members(target, offset)
except FloodWait as e: # Very large chats could trigger FloodWait
time.sleep(e.x) # When it happens, wait X seconds and try again
continue
if not chunk.chat_members:
break # No more members left
members.extend(chunk.chat_members)
offset += len(chunk.chat_members)
# Now the "members" list contains all the members of the target chat

View File

@ -1,50 +0,0 @@
"""This is an improved version of get_chat_members.py
Since Telegram will return at most 10.000 members for a single query, this script
repeats the search using numbers ("0" to "9") and all the available ascii letters ("a" to "z").
This can be further improved by also searching for non-ascii characters (e.g.: Japanese script),
as some user names may not contain ascii letters at all.
"""
import time
from string import ascii_lowercase
from pyrogram import Client
from pyrogram.api.errors import FloodWait
app = Client("my_account")
target = "pyrogramchat" # Target channel/supergroup
members = {} # List that will contain all the members of the target chat
limit = 200 # Amount of users to retrieve for each API call (max 200)
# "" + "0123456789" + "abcdefghijklmnopqrstuvwxyz" (as list)
queries = [""] + [str(i) for i in range(10)] + list(ascii_lowercase)
with app:
for q in queries:
print('Searching for "{}"'.format(q))
offset = 0 # For each query, offset restarts from 0
while True:
try:
chunk = app.get_chat_members(target, offset, query=q)
except FloodWait as e: # Very large chats could trigger FloodWait
print("Flood wait: {} seconds".format(e.x))
time.sleep(e.x) # When it happens, wait X seconds and try again
continue
if not chunk.chat_members:
print('Done searching for "{}"'.format(q))
print()
break # No more members left
members.update({i.user.id: i for i in chunk.chat_members})
offset += len(chunk.chat_members)
print("Total members: {}".format(len(members)))
print("Grand total: {}".format(len(members)))
# Now the "members" list contains all the members of the target chat

View File

@ -1,31 +0,0 @@
"""This example shows how to retrieve the full message history of a chat"""
import time
from pyrogram import Client
from pyrogram.api.errors import FloodWait
app = Client("my_account")
target = "me" # "me" refers to your own chat (Saved Messages)
messages = [] # List that will contain all the messages of the target chat
offset_id = 0 # ID of the last message of the chunk
with app:
while True:
try:
m = app.get_history(target, offset_id=offset_id)
except FloodWait as e: # For very large chats the method call can raise a FloodWait
print("waiting {}".format(e.x))
time.sleep(e.x) # Sleep X seconds before continuing
continue
if not m.messages:
break
messages += m.messages
offset_id = m.messages[-1].message_id
print("Messages: {}".format(len(messages)))
# Now the "messages" list contains all the messages sorted by date in
# descending order (from the most recent to the oldest one)

16
examples/hello.py Normal file
View File

@ -0,0 +1,16 @@
"""This example demonstrates a basic API usage"""
from pyrogram import Client
# Create a new Client instance
app = Client("my_account")
with app:
# Send a message, Markdown is enabled by default
app.send_message("me", "Hi there! I'm using **Pyrogram**")
# Send a location
app.send_location("me", 51.500729, -0.124583)
# Send a sticker
app.send_sticker("me", "CAADBAADhw4AAvLQYAHICbZ5SUs_jwI")

View File

@ -1,18 +0,0 @@
"""This example demonstrates a basic API usage"""
from pyrogram import Client
# Create a new Client instance
app = Client("my_account")
# Start the Client before calling any API method
app.start()
# Send a message to yourself, Markdown is enabled by default
app.send_message("me", "Hi there! I'm using **Pyrogram**")
# Send a location to yourself
app.send_location("me", 51.500729, -0.124583)
# Stop the client when you're done
app.stop()

10
examples/history.py Normal file
View File

@ -0,0 +1,10 @@
"""This example shows how to get the full message history of a chat, starting from the latest message"""
from pyrogram import Client
app = Client("my_account")
target = "me" # "me" refers to your own chat (Saved Messages)
with app:
for message in app.iter_history(target):
print(message.text)

59
examples/keyboards.py Normal file
View File

@ -0,0 +1,59 @@
"""This example will show you how to send normal and inline keyboards.
You must log-in as a regular bot in order to send keyboards (use the token from @BotFather).
Any attempt in sending keyboards with a user account will be simply ignored by the server.
send_message() is used as example, but a keyboard can be sent with any other send_* methods,
like send_audio(), send_document(), send_location(), etc...
"""
from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
# Create a client using your bot token
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
with app:
app.send_message(
"haskell", # Edit this
"This is a ReplyKeyboardMarkup example",
reply_markup=ReplyKeyboardMarkup(
[
["A", "B", "C", "D"], # First row
["E", "F", "G"], # Second row
["H", "I"], # Third row
["J"] # Fourth row
],
resize_keyboard=True # Make the keyboard smaller
)
)
app.send_message(
"haskell", # Edit this
"This is a InlineKeyboardMarkup example",
reply_markup=InlineKeyboardMarkup(
[
[ # First row
InlineKeyboardButton( # Generates a callback query when pressed
"Button",
callback_data=b"data"
), # Note how callback_data must be bytes
InlineKeyboardButton( # Opens a web URL
"URL",
url="https://docs.pyrogram.ml"
),
],
[ # Second row
# Opens the inline interface
InlineKeyboardButton(
"Choose chat",
switch_inline_query="pyrogram"
),
InlineKeyboardButton( # Opens the inline interface in the current chat
"Inline here",
switch_inline_query_current_chat="pyrogram"
)
]
]
)
)

View File

@ -1,51 +0,0 @@
"""This example will show you how to send normal and inline keyboards.
You must log-in as a regular bot in order to send keyboards (use the token from @BotFather).
Any attempt in sending keyboards with a user account will be simply ignored by the server.
send_message() is used as example, but a keyboard can be sent with any other send_* methods,
like send_audio(), send_document(), send_location(), etc...
"""
from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
# Create a client using your bot token
app = Client("123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11")
app.start()
app.send_message(
"haskell", # Edit this
"This is a ReplyKeyboardMarkup example",
reply_markup=ReplyKeyboardMarkup(
[
["A", "B", "C", "D"], # First row
["E", "F", "G"], # Second row
["H", "I"], # Third row
["J"] # Fourth row
],
resize_keyboard=True # Make the keyboard smaller
)
)
app.send_message(
"haskell", # Edit this
"This is a InlineKeyboardMarkup example",
reply_markup=InlineKeyboardMarkup(
[
[ # First row
# Generates a callback query when pressed
InlineKeyboardButton("Button", callback_data="data"),
# Opens a web URL
InlineKeyboardButton("URL", url="https://docs.pyrogram.ml"),
],
[ # Second row
# Opens the inline interface of a bot in another chat with a pre-defined query
InlineKeyboardButton("Choose chat", switch_inline_query="pyrogram"),
# Same as the button above, but the inline interface is opened in the current chat
InlineKeyboardButton("Inline here", switch_inline_query_current_chat="pyrogram"),
]
]
)
)
app.stop()

27
examples/welcome.py Normal file
View File

@ -0,0 +1,27 @@
"""This is the Welcome Bot in @PyrogramChat.
It uses the Emoji module to easily add emojis in your text messages and Filters
to make it only work for specific messages in a specific chat.
"""
from pyrogram import Client, Emoji, Filters
MENTION = "[{}](tg://user?id={})"
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {}!"
app = Client("my_account")
@app.on_message(Filters.chat("PyrogramChat") & Filters.new_chat_members)
def welcome(client, message):
# Build the new members list (with mentions) by using their first_name
new_members = [MENTION.format(i.first_name, i.id) for i in message.new_chat_members]
# Build the welcome message by using an emoji and the list we built above
text = MESSAGE.format(Emoji.SPARKLES, ", ".join(new_members))
# Send the welcome message, without the web page preview
message.reply(text, disable_web_page_preview=True)
app.run() # Automatically start() and idle()

View File

@ -1,45 +0,0 @@
"""This is the Welcome Bot in @PyrogramChat.
It uses the Emoji module to easily add emojis in your text messages and Filters
to make it only work for specific messages in a specific chat.
"""
from pyrogram import Client, Emoji, Filters
USER = "**{}**"
MESSAGE = "{} Welcome to [Pyrogram](https://docs.pyrogram.ml/)'s group chat {{}}!".format(Emoji.SPARKLES)
enabled_groups = Filters.chat("PyrogramChat")
last_welcomes = {}
app = Client("my_account")
@app.on_message(enabled_groups & Filters.new_chat_members)
def welcome(client, message):
chat_id = message.chat.id
# Get the previous welcome message and members, if any
previous_welcome, previous_members = last_welcomes.pop(chat_id, (None, []))
# Delete the previous message, if exists
if previous_welcome:
previous_welcome.delete()
# Build the new members list by using their first_name. Also append the previous members, if any
new_members = [USER.format(i.first_name) for i in message.new_chat_members] + previous_members
# Build the welcome message by using an emoji and the list we created above
text = MESSAGE.format(", ".join(new_members))
# Actually send the welcome and save the new message and the new members list
last_welcomes[message.chat.id] = message.reply(text, disable_web_page_preview=True), new_members
@app.on_message(enabled_groups)
def reset(client, message):
# Don't make the bot delete the previous welcome in case someone talks in the middle
last_welcomes.pop(message.chat.id, None)
app.run() # Automatically start() and idle()

View File

@ -89,6 +89,7 @@ class IterChatMembers(BaseClient):
yielded = set() yielded = set()
queries = [query] if query else QUERIES queries = [query] if query else QUERIES
total = limit or (1 << 31) - 1 total = limit or (1 << 31) - 1
filter = Filters.RECENT if total <= 10000 and filter == Filters.ALL else filter
limit = min(200, total) limit = min(200, total)
if filter not in QUERYABLE_FILTERS: if filter not in QUERYABLE_FILTERS:

View File

@ -16,7 +16,7 @@
# You should have received a copy of the GNU Lesser General Public License # You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>. # along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import List from typing import List, Union
from pyrogram.api.types import KeyboardButtonRow from pyrogram.api.types import KeyboardButtonRow
from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup from pyrogram.api.types import ReplyKeyboardMarkup as RawReplyKeyboardMarkup
@ -50,7 +50,7 @@ class ReplyKeyboardMarkup(PyrogramType):
""" """
def __init__(self, def __init__(self,
keyboard: List[List[KeyboardButton]], keyboard: List[List[Union[KeyboardButton, str]]],
resize_keyboard: bool = None, resize_keyboard: bool = None,
one_time_keyboard: bool = None, one_time_keyboard: bool = None,
selective: bool = None): selective: bool = None):