mirror of
https://github.com/pyrogram/pyrogram
synced 2025-09-02 23:35:17 +00:00
Merge branch 'develop' into layer-95
# Conflicts: # pyrogram/__init__.py
This commit is contained in:
@@ -18,12 +18,18 @@
|
||||
|
||||
import sys
|
||||
|
||||
if sys.version_info[:3] in [(3, 5, 0), (3, 5, 1), (3, 5, 2)]:
|
||||
from .vendor import typing
|
||||
|
||||
# Monkey patch the standard "typing" module because Python versions from 3.5.0 to 3.5.2 have a broken one.
|
||||
sys.modules["typing"] = typing
|
||||
|
||||
__copyright__ = "Copyright (C) 2017-2019 Dan Tès <https://github.com/delivrance>".replace(
|
||||
"\xe8",
|
||||
"e" if sys.getfilesystemencoding() != "utf-8" else "\xe8"
|
||||
)
|
||||
__license__ = "GNU Lesser General Public License v3 or later (LGPLv3+)"
|
||||
__version__ = "0.10.4.develop"
|
||||
__version__ = "0.11.1.develop"
|
||||
|
||||
from .api.errors import Error
|
||||
from .client.types import (
|
||||
@@ -32,8 +38,8 @@ from .client.types import (
|
||||
Location, Message, MessageEntity, Dialog, Dialogs, Photo, PhotoSize, Sticker, User, UserStatus,
|
||||
UserProfilePhotos, Venue, Animation, Video, VideoNote, Voice, CallbackQuery, Messages, ForceReply,
|
||||
InlineKeyboardButton, InlineKeyboardMarkup, KeyboardButton, ReplyKeyboardMarkup, ReplyKeyboardRemove,
|
||||
Poll, PollOption, ChatPreview, StopPropagation, Game, CallbackGame, GameHighScore, GameHighScores,
|
||||
ChatPermissions
|
||||
Poll, PollOption, ChatPreview, StopPropagation, ContinuePropagation, Game, CallbackGame, GameHighScore,
|
||||
GameHighScores, ChatPermissions
|
||||
)
|
||||
from .client import (
|
||||
Client, ChatAction, ParseMode, Emoji,
|
||||
|
@@ -29,6 +29,7 @@ import struct
|
||||
import tempfile
|
||||
import threading
|
||||
import time
|
||||
import warnings
|
||||
from configparser import ConfigParser
|
||||
from datetime import datetime
|
||||
from hashlib import sha256, md5
|
||||
@@ -67,10 +68,10 @@ class Client(Methods, BaseClient):
|
||||
|
||||
Args:
|
||||
session_name (``str``):
|
||||
Name to uniquely identify a session of either a User or a Bot.
|
||||
For Users: pass a string of your choice, e.g.: "my_main_account".
|
||||
For Bots: pass your Bot API token, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
Note: as long as a valid User session file exists, Pyrogram won't ask you again to input your phone number.
|
||||
Name to uniquely identify a session of either a User or a Bot, e.g.: "my_account". This name will be used
|
||||
to save a file to disk that stores details needed for reconnecting without asking again for credentials.
|
||||
Note for bots: You can pass a bot token here, but this usage will be deprecated in next releases.
|
||||
Use *bot_token* instead.
|
||||
|
||||
api_id (``int``, *optional*):
|
||||
The *api_id* part of your Telegram API Key, as integer. E.g.: 12345
|
||||
@@ -139,8 +140,13 @@ class Client(Methods, BaseClient):
|
||||
Only applicable for new sessions.
|
||||
|
||||
first_name (``str``, *optional*):
|
||||
Pass a First Name to avoid entering it manually. It will be used to automatically
|
||||
create a new Telegram account in case the phone number you passed is not registered yet.
|
||||
Pass a First Name as string to avoid entering it manually. Or pass a callback function which accepts no
|
||||
arguments and must return the correct name as string (e.g., "Dan"). It will be used to automatically create
|
||||
a new Telegram account in case the phone number you passed is not registered yet.
|
||||
Only applicable for new sessions.
|
||||
|
||||
bot_token (``str``, *optional*):
|
||||
Pass your Bot API token to create a bot session, e.g.: "123456:ABC-DEF1234ghIkl-zyx57W2v1u123ew11"
|
||||
Only applicable for new sessions.
|
||||
|
||||
last_name (``str``, *optional*):
|
||||
@@ -157,10 +163,9 @@ 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).
|
||||
plugins (``dict``, *optional*):
|
||||
Your Smart Plugins settings as dict, e.g.: *dict(root="plugins")*.
|
||||
This is an alternative way to setup plugins if you don't want to use the *config.ini* file.
|
||||
|
||||
no_updates (``bool``, *optional*):
|
||||
Pass True to completely disable incoming updates for the current session.
|
||||
@@ -192,12 +197,13 @@ class Client(Methods, BaseClient):
|
||||
password: str = None,
|
||||
recovery_code: callable = None,
|
||||
force_sms: bool = False,
|
||||
bot_token: str = None,
|
||||
first_name: str = None,
|
||||
last_name: str = None,
|
||||
workers: int = BaseClient.WORKERS,
|
||||
workdir: str = BaseClient.WORKDIR,
|
||||
config_file: str = BaseClient.CONFIG_FILE,
|
||||
plugins_dir: str = None,
|
||||
plugins: dict = None,
|
||||
no_updates: bool = None,
|
||||
takeout: bool = None):
|
||||
super().__init__()
|
||||
@@ -218,12 +224,13 @@ class Client(Methods, BaseClient):
|
||||
self.password = password
|
||||
self.recovery_code = recovery_code
|
||||
self.force_sms = force_sms
|
||||
self.bot_token = bot_token
|
||||
self.first_name = first_name
|
||||
self.last_name = last_name
|
||||
self.workers = workers
|
||||
self.workdir = workdir
|
||||
self.config_file = config_file
|
||||
self.plugins_dir = plugins_dir
|
||||
self.plugins = plugins
|
||||
self.no_updates = no_updates
|
||||
self.takeout = takeout
|
||||
|
||||
@@ -263,8 +270,13 @@ class Client(Methods, BaseClient):
|
||||
raise ConnectionError("Client has already been started")
|
||||
|
||||
if self.BOT_TOKEN_RE.match(self.session_name):
|
||||
self.is_bot = True
|
||||
self.bot_token = self.session_name
|
||||
self.session_name = self.session_name.split(":")[0]
|
||||
warnings.warn('\nYou are using a bot token as session name.\n'
|
||||
'It will be deprecated in next update, please use session file name to load '
|
||||
'existing sessions and bot_token argument to create new sessions.',
|
||||
DeprecationWarning, stacklevel=2)
|
||||
|
||||
self.load_config()
|
||||
self.load_session()
|
||||
@@ -282,13 +294,15 @@ class Client(Methods, BaseClient):
|
||||
try:
|
||||
if self.user_id is None:
|
||||
if self.bot_token is None:
|
||||
self.is_bot = False
|
||||
self.authorize_user()
|
||||
else:
|
||||
self.is_bot = True
|
||||
self.authorize_bot()
|
||||
|
||||
self.save_session()
|
||||
|
||||
if self.bot_token is None:
|
||||
if not self.is_bot:
|
||||
if self.takeout:
|
||||
self.takeout_id = self.send(functions.account.InitTakeoutSession()).id
|
||||
log.warning("Takeout session {} initiated".format(self.takeout_id))
|
||||
@@ -1075,6 +1089,31 @@ class Client(Methods, BaseClient):
|
||||
self._proxy["username"] = parser.get("proxy", "username", fallback=None) or None
|
||||
self._proxy["password"] = parser.get("proxy", "password", fallback=None) or None
|
||||
|
||||
if self.plugins:
|
||||
self.plugins["enabled"] = bool(self.plugins.get("enabled", True))
|
||||
self.plugins["include"] = "\n".join(self.plugins.get("include", [])) or None
|
||||
self.plugins["exclude"] = "\n".join(self.plugins.get("exclude", [])) or None
|
||||
else:
|
||||
try:
|
||||
section = parser["plugins"]
|
||||
|
||||
self.plugins = {
|
||||
"enabled": section.getboolean("enabled", True),
|
||||
"root": section.get("root"),
|
||||
"include": section.get("include") or None,
|
||||
"exclude": section.get("exclude") or None
|
||||
}
|
||||
except KeyError:
|
||||
self.plugins = {}
|
||||
|
||||
if self.plugins:
|
||||
for option in ["include", "exclude"]:
|
||||
if self.plugins[option] is not None:
|
||||
self.plugins[option] = [
|
||||
(i.split()[0], i.split()[1:] or None)
|
||||
for i in self.plugins[option].strip().split("\n")
|
||||
]
|
||||
|
||||
def load_session(self):
|
||||
try:
|
||||
with open(os.path.join(self.workdir, "{}.session".format(self.session_name)), encoding="utf-8") as f:
|
||||
@@ -1089,6 +1128,8 @@ class Client(Methods, BaseClient):
|
||||
self.auth_key = base64.b64decode("".join(s["auth_key"]))
|
||||
self.user_id = s["user_id"]
|
||||
self.date = s.get("date", 0)
|
||||
# TODO: replace default with False once token session name will be deprecated
|
||||
self.is_bot = s.get("is_bot", self.is_bot)
|
||||
|
||||
for k, v in s.get("peers_by_id", {}).items():
|
||||
self.peers_by_id[int(k)] = utils.get_input_peer(int(k), v)
|
||||
@@ -1106,43 +1147,108 @@ class Client(Methods, BaseClient):
|
||||
self.peers_by_phone[k] = peer
|
||||
|
||||
def load_plugins(self):
|
||||
if self.plugins_dir is not None:
|
||||
plugins_count = 0
|
||||
if self.plugins.get("enabled", False):
|
||||
root = self.plugins["root"]
|
||||
include = self.plugins["include"]
|
||||
exclude = self.plugins["exclude"]
|
||||
|
||||
for path in Path(self.plugins_dir).rglob("*.py"):
|
||||
file_path = os.path.splitext(str(path))[0]
|
||||
import_path = []
|
||||
count = 0
|
||||
|
||||
while file_path:
|
||||
file_path, tail = os.path.split(file_path)
|
||||
import_path.insert(0, tail)
|
||||
if include is None:
|
||||
for path in sorted(Path(root).rglob("*.py")):
|
||||
module_path = '.'.join(path.parent.parts + (path.stem,))
|
||||
module = import_module(module_path)
|
||||
|
||||
import_path = ".".join(import_path)
|
||||
module = import_module(import_path)
|
||||
for name in vars(module).keys():
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
handler, group = getattr(module, name)
|
||||
|
||||
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)
|
||||
|
||||
if isinstance(handler, Handler) and isinstance(group, int):
|
||||
self.add_handler(handler, group)
|
||||
log.info('[LOAD] {}("{}") in group {} from "{}"'.format(
|
||||
type(handler).__name__, name, group, module_path))
|
||||
|
||||
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
|
||||
))
|
||||
count += 1
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
log.warning('No plugin loaded: "{}" doesn\'t contain any valid plugin'.format(self.plugins_dir))
|
||||
for path, handlers in include:
|
||||
module_path = root + "." + path
|
||||
warn_non_existent_functions = True
|
||||
|
||||
try:
|
||||
module = import_module(module_path)
|
||||
except ModuleNotFoundError:
|
||||
log.warning('[LOAD] Ignoring non-existent module "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
if "__path__" in dir(module):
|
||||
log.warning('[LOAD] Ignoring namespace "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
if handlers is None:
|
||||
handlers = vars(module).keys()
|
||||
warn_non_existent_functions = False
|
||||
|
||||
for name in handlers:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
handler, group = getattr(module, name)
|
||||
|
||||
if isinstance(handler, Handler) and isinstance(group, int):
|
||||
self.add_handler(handler, group)
|
||||
|
||||
log.info('[LOAD] {}("{}") in group {} from "{}"'.format(
|
||||
type(handler).__name__, name, group, module_path))
|
||||
|
||||
count += 1
|
||||
except Exception:
|
||||
if warn_non_existent_functions:
|
||||
log.warning('[LOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
||||
name, module_path))
|
||||
|
||||
if exclude is not None:
|
||||
for path, handlers in exclude:
|
||||
module_path = root + "." + path
|
||||
warn_non_existent_functions = True
|
||||
|
||||
try:
|
||||
module = import_module(module_path)
|
||||
except ModuleNotFoundError:
|
||||
log.warning('[UNLOAD] Ignoring non-existent module "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
if "__path__" in dir(module):
|
||||
log.warning('[UNLOAD] Ignoring namespace "{}"'.format(module_path))
|
||||
continue
|
||||
|
||||
if handlers is None:
|
||||
handlers = vars(module).keys()
|
||||
warn_non_existent_functions = False
|
||||
|
||||
for name in handlers:
|
||||
# noinspection PyBroadException
|
||||
try:
|
||||
handler, group = getattr(module, name)
|
||||
|
||||
if isinstance(handler, Handler) and isinstance(group, int):
|
||||
self.remove_handler(handler, group)
|
||||
|
||||
log.info('[UNLOAD] {}("{}") from group {} in "{}"'.format(
|
||||
type(handler).__name__, name, group, module_path))
|
||||
|
||||
count -= 1
|
||||
except Exception:
|
||||
if warn_non_existent_functions:
|
||||
log.warning('[UNLOAD] Ignoring non-existent function "{}" from "{}"'.format(
|
||||
name, module_path))
|
||||
|
||||
if count > 0:
|
||||
log.warning('Successfully loaded {} plugin{} from "{}"'.format(count, "s" if count > 1 else "", root))
|
||||
else:
|
||||
log.warning('No plugin loaded from "{}"'.format(root))
|
||||
|
||||
def save_session(self):
|
||||
auth_key = base64.b64encode(self.auth_key).decode()
|
||||
@@ -1157,7 +1263,8 @@ class Client(Methods, BaseClient):
|
||||
test_mode=self.test_mode,
|
||||
auth_key=auth_key,
|
||||
user_id=self.user_id,
|
||||
date=self.date
|
||||
date=self.date,
|
||||
is_bot=self.is_bot,
|
||||
),
|
||||
f,
|
||||
indent=4
|
||||
@@ -1350,21 +1457,25 @@ class Client(Methods, BaseClient):
|
||||
md5_sum = "".join([hex(i)[2:].zfill(2) for i in md5_sum.digest()])
|
||||
break
|
||||
|
||||
if is_big:
|
||||
rpc = functions.upload.SaveBigFilePart(
|
||||
file_id=file_id,
|
||||
file_part=file_part,
|
||||
file_total_parts=file_total_parts,
|
||||
bytes=chunk
|
||||
)
|
||||
else:
|
||||
rpc = functions.upload.SaveFilePart(
|
||||
file_id=file_id,
|
||||
file_part=file_part,
|
||||
bytes=chunk
|
||||
)
|
||||
for _ in range(3):
|
||||
if is_big:
|
||||
rpc = functions.upload.SaveBigFilePart(
|
||||
file_id=file_id,
|
||||
file_part=file_part,
|
||||
file_total_parts=file_total_parts,
|
||||
bytes=chunk
|
||||
)
|
||||
else:
|
||||
rpc = functions.upload.SaveFilePart(
|
||||
file_id=file_id,
|
||||
file_part=file_part,
|
||||
bytes=chunk
|
||||
)
|
||||
|
||||
assert session.send(rpc), "Couldn't upload file"
|
||||
if session.send(rpc):
|
||||
break
|
||||
else:
|
||||
raise AssertionError("Telegram didn't accept chunk #{} of {}".format(file_part, path))
|
||||
|
||||
if is_missing_part:
|
||||
return
|
||||
|
@@ -128,35 +128,37 @@ class Dispatcher:
|
||||
|
||||
parser = self.update_parsers.get(type(update), None)
|
||||
|
||||
if parser is None:
|
||||
continue
|
||||
|
||||
parsed_update, handler_type = parser(update, users, chats)
|
||||
parsed_update, handler_type = (
|
||||
parser(update, users, chats)
|
||||
if parser is not None
|
||||
else (None, type(None))
|
||||
)
|
||||
|
||||
for group in self.groups.values():
|
||||
try:
|
||||
for handler in group:
|
||||
args = None
|
||||
for handler in group:
|
||||
args = None
|
||||
|
||||
if isinstance(handler, RawUpdateHandler):
|
||||
args = (update, users, chats)
|
||||
elif isinstance(handler, handler_type):
|
||||
if handler.check(parsed_update):
|
||||
args = (parsed_update,)
|
||||
if isinstance(handler, handler_type):
|
||||
if handler.check(parsed_update):
|
||||
args = (parsed_update,)
|
||||
elif isinstance(handler, RawUpdateHandler):
|
||||
args = (update, users, chats)
|
||||
|
||||
if args is None:
|
||||
continue
|
||||
if args is None:
|
||||
continue
|
||||
|
||||
try:
|
||||
handler.callback(self.client, *args)
|
||||
except StopIteration:
|
||||
raise
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
try:
|
||||
handler.callback(self.client, *args)
|
||||
except pyrogram.StopPropagation:
|
||||
raise
|
||||
except pyrogram.ContinuePropagation:
|
||||
continue
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
break
|
||||
except StopIteration:
|
||||
break
|
||||
except pyrogram.StopPropagation:
|
||||
pass
|
||||
except Exception as e:
|
||||
log.error(e, exc_info=True)
|
||||
|
||||
|
@@ -68,7 +68,7 @@ class BaseClient:
|
||||
}
|
||||
|
||||
def __init__(self):
|
||||
self.bot_token = None
|
||||
self.is_bot = None
|
||||
self.dc_id = None
|
||||
self.auth_key = None
|
||||
self.user_id = None
|
||||
|
@@ -94,6 +94,7 @@ class Syncer:
|
||||
auth_key=auth_key,
|
||||
user_id=client.user_id,
|
||||
date=int(time.time()),
|
||||
is_bot=client.is_bot,
|
||||
peers_by_id={
|
||||
k: getattr(v, "access_hash", None)
|
||||
for k, v in client.peers_by_id.copy().items()
|
||||
|
@@ -62,16 +62,16 @@ class Filters:
|
||||
create = create
|
||||
|
||||
me = create("Me", lambda _, m: bool(m.from_user and m.from_user.is_self))
|
||||
"""Filter messages coming from you yourself"""
|
||||
"""Filter messages generated by you yourself."""
|
||||
|
||||
bot = create("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
|
||||
"""Filter messages coming from bots"""
|
||||
"""Filter messages coming from bots."""
|
||||
|
||||
incoming = create("Incoming", lambda _, m: not m.outgoing)
|
||||
"""Filter incoming messages."""
|
||||
"""Filter incoming messages. Messages sent to your own chat (Saved Messages) are also recognised as incoming."""
|
||||
|
||||
outgoing = create("Outgoing", lambda _, m: m.outgoing)
|
||||
"""Filter outgoing messages."""
|
||||
"""Filter outgoing messages. Messages sent to your own chat (Saved Messages) are not recognized as outgoing."""
|
||||
|
||||
text = create("Text", lambda _, m: bool(m.text))
|
||||
"""Filter text messages."""
|
||||
|
@@ -45,10 +45,3 @@ class CallbackQueryHandler(Handler):
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, callback_query):
|
||||
return (
|
||||
self.filters(callback_query)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@@ -48,8 +48,4 @@ class DeletedMessagesHandler(Handler):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, messages):
|
||||
return (
|
||||
self.filters(messages.messages[0])
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
return super().check(messages.messages[0])
|
||||
|
@@ -21,3 +21,10 @@ class Handler:
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
self.callback = callback
|
||||
self.filters = filters
|
||||
|
||||
def check(self, update):
|
||||
return (
|
||||
self.filters(update)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@@ -46,10 +46,3 @@ class MessageHandler(Handler):
|
||||
|
||||
def __init__(self, callback: callable, filters=None):
|
||||
super().__init__(callback, filters)
|
||||
|
||||
def check(self, message):
|
||||
return (
|
||||
self.filters(message)
|
||||
if callable(self.filters)
|
||||
else True
|
||||
)
|
||||
|
@@ -45,10 +45,3 @@ class UserStatusHandler(Handler):
|
||||
|
||||
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
|
||||
)
|
||||
|
@@ -37,6 +37,7 @@ from .set_chat_photo import SetChatPhoto
|
||||
from .set_chat_title import SetChatTitle
|
||||
from .unban_chat_member import UnbanChatMember
|
||||
from .unpin_chat_message import UnpinChatMessage
|
||||
from .update_chat_username import UpdateChatUsername
|
||||
|
||||
|
||||
class Chats(
|
||||
@@ -60,6 +61,7 @@ class Chats(
|
||||
GetChatMembersCount,
|
||||
GetChatPreview,
|
||||
IterDialogs,
|
||||
IterChatMembers
|
||||
IterChatMembers,
|
||||
UpdateChatUsername
|
||||
):
|
||||
pass
|
||||
|
@@ -16,6 +16,7 @@
|
||||
# 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.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
@@ -30,17 +31,24 @@ class JoinChat(BaseClient):
|
||||
Unique identifier for the target chat in form of a *t.me/joinchat/* link or username of the target
|
||||
channel/supergroup (in the format @username).
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Chat <pyrogram.Chat>` object is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
match = self.INVITE_LINK_RE.match(chat_id)
|
||||
|
||||
if match:
|
||||
return self.send(
|
||||
chat = self.send(
|
||||
functions.messages.ImportChatInvite(
|
||||
hash=match.group(1)
|
||||
)
|
||||
)
|
||||
if isinstance(chat.chats[0], types.Chat):
|
||||
return pyrogram.Chat._parse_chat_chat(self, chat.chats[0])
|
||||
elif isinstance(chat.chats[0], types.Channel):
|
||||
return pyrogram.Chat._parse_channel_chat(self, chat.chats[0])
|
||||
else:
|
||||
resolved_peer = self.send(
|
||||
functions.contacts.ResolveUsername(
|
||||
@@ -53,8 +61,10 @@ class JoinChat(BaseClient):
|
||||
access_hash=resolved_peer.chats[0].access_hash
|
||||
)
|
||||
|
||||
return self.send(
|
||||
chat = self.send(
|
||||
functions.channels.JoinChannel(
|
||||
channel=channel
|
||||
)
|
||||
)
|
||||
|
||||
return pyrogram.Chat._parse_channel_chat(self, chat.chats[0])
|
||||
|
59
pyrogram/client/methods/chats/update_chat_username.py
Normal file
59
pyrogram/client/methods/chats/update_chat_username.py
Normal file
@@ -0,0 +1,59 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 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 typing import Union
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class UpdateChatUsername(BaseClient):
|
||||
def update_chat_username(self,
|
||||
chat_id: Union[int, str],
|
||||
username: Union[str, None]) -> bool:
|
||||
"""Use this method to update a channel or a supergroup username.
|
||||
|
||||
To update your own username (for users only, not bots) you can use :meth:`update_username`.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``)
|
||||
Unique identifier (int) or username (str) of the target chat.
|
||||
username (``str`` | ``None``):
|
||||
Username to set. Pass "" (empty string) or None to remove the username.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
``ValueError`` if a chat_id belongs to a user or chat.
|
||||
"""
|
||||
|
||||
peer = self.resolve_peer(chat_id)
|
||||
|
||||
if isinstance(peer, types.InputPeerChannel):
|
||||
return bool(
|
||||
self.send(
|
||||
functions.channels.UpdateUsername(
|
||||
channel=peer,
|
||||
username=username or ""
|
||||
)
|
||||
)
|
||||
)
|
||||
else:
|
||||
raise ValueError("The chat_id \"{}\" belongs to a user or chat".format(chat_id))
|
@@ -19,7 +19,8 @@
|
||||
import logging
|
||||
import time
|
||||
|
||||
from pyrogram.api import functions, types
|
||||
import pyrogram
|
||||
from pyrogram.api import functions
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
@@ -28,12 +29,10 @@ log = logging.getLogger(__name__)
|
||||
|
||||
class GetContacts(BaseClient):
|
||||
def get_contacts(self):
|
||||
"""Use this method to get contacts from your Telegram address book
|
||||
|
||||
Requires no parameters.
|
||||
"""Use this method to get contacts from your Telegram address book.
|
||||
|
||||
Returns:
|
||||
On success, the user's contacts are returned
|
||||
On success, a list of :obj:`User` objects is returned.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
@@ -44,9 +43,6 @@ class GetContacts(BaseClient):
|
||||
except FloodWait as e:
|
||||
log.warning("get_contacts flood: waiting {} seconds".format(e.x))
|
||||
time.sleep(e.x)
|
||||
continue
|
||||
else:
|
||||
if isinstance(contacts, types.contacts.Contacts):
|
||||
log.info("Total contacts: {}".format(len(self.peers_by_phone)))
|
||||
|
||||
return contacts
|
||||
log.info("Total contacts: {}".format(len(self.peers_by_phone)))
|
||||
return [pyrogram.User._parse(self, user) for user in contacts.users]
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -122,7 +121,8 @@ class EditMessageMedia(BaseClient):
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
mime_type="video/mp4",
|
||||
thumb=None if media.thumb is None else self.save_file(media.thumb),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
@@ -178,7 +178,8 @@ class EditMessageMedia(BaseClient):
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "audio/mpeg"),
|
||||
mime_type="audio/mpeg",
|
||||
thumb=None if media.thumb is None else self.save_file(media.thumb),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeAudio(
|
||||
@@ -233,7 +234,8 @@ class EditMessageMedia(BaseClient):
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
mime_type="video/mp4",
|
||||
thumb=None if media.thumb is None else self.save_file(media.thumb),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
@@ -290,7 +292,8 @@ class EditMessageMedia(BaseClient):
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + media.media.split(".")[-1], "text/plain"),
|
||||
mime_type="application/zip",
|
||||
thumb=None if media.thumb is None else self.save_file(media.thumb),
|
||||
file=self.save_file(media.media),
|
||||
attributes=[
|
||||
types.DocumentAttributeFilename(os.path.basename(media.media))
|
||||
|
@@ -16,12 +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/>.
|
||||
|
||||
import logging
|
||||
import time
|
||||
from typing import Union
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions
|
||||
from pyrogram.api.errors import FloodWait
|
||||
from ...ext import BaseClient
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class GetHistory(BaseClient):
|
||||
def get_history(self,
|
||||
@@ -66,21 +71,28 @@ class GetHistory(BaseClient):
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
messages = pyrogram.Messages._parse(
|
||||
self,
|
||||
self.send(
|
||||
functions.messages.GetHistory(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
offset_id=offset_id,
|
||||
offset_date=offset_date,
|
||||
add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0),
|
||||
limit=limit,
|
||||
max_id=0,
|
||||
min_id=0,
|
||||
hash=0
|
||||
while True:
|
||||
try:
|
||||
messages = pyrogram.Messages._parse(
|
||||
self,
|
||||
self.send(
|
||||
functions.messages.GetHistory(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
offset_id=offset_id,
|
||||
offset_date=offset_date,
|
||||
add_offset=offset * (-1 if reverse else 1) - (limit if reverse else 0),
|
||||
limit=limit,
|
||||
max_id=0,
|
||||
min_id=0,
|
||||
hash=0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
time.sleep(e.x)
|
||||
else:
|
||||
break
|
||||
|
||||
if reverse:
|
||||
messages.messages.reverse()
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -132,7 +131,7 @@ class SendAnimation(BaseClient):
|
||||
thumb = None if thumb is None else self.save_file(thumb)
|
||||
file = self.save_file(animation, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
mime_type="video/mp4",
|
||||
file=file,
|
||||
thumb=thumb,
|
||||
attributes=[
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -134,7 +133,7 @@ class SendAudio(BaseClient):
|
||||
thumb = None if thumb is None else self.save_file(thumb)
|
||||
file = self.save_file(audio, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + audio.split(".")[-1], "audio/mpeg"),
|
||||
mime_type="audio/mpeg",
|
||||
file=file,
|
||||
thumb=thumb,
|
||||
attributes=[
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -120,7 +119,7 @@ class SendDocument(BaseClient):
|
||||
thumb = None if thumb is None else self.save_file(thumb)
|
||||
file = self.save_file(document, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + document.split(".")[-1], "text/plain"),
|
||||
mime_type="application/zip",
|
||||
file=file,
|
||||
thumb=thumb,
|
||||
attributes=[
|
||||
|
@@ -17,20 +17,22 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import logging
|
||||
import os
|
||||
import struct
|
||||
import time
|
||||
from typing import Union, List
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.api import functions, types
|
||||
from pyrogram.api.errors import FileIdInvalid
|
||||
from pyrogram.api.errors import FileIdInvalid, FloodWait
|
||||
from pyrogram.client.ext import BaseClient, utils
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class SendMediaGroup(BaseClient):
|
||||
# TODO: Add progress parameter
|
||||
# TODO: Return new Message object
|
||||
# TODO: Figure out how to send albums using URLs
|
||||
def send_media_group(self,
|
||||
chat_id: Union[int, str],
|
||||
@@ -38,7 +40,6 @@ class SendMediaGroup(BaseClient):
|
||||
disable_notification: bool = None,
|
||||
reply_to_message_id: int = None):
|
||||
"""Use this method to send a group of photos or videos as an album.
|
||||
On success, an Update containing the sent Messages is returned.
|
||||
|
||||
Args:
|
||||
chat_id (``int`` | ``str``):
|
||||
@@ -57,6 +58,13 @@ class SendMediaGroup(BaseClient):
|
||||
|
||||
reply_to_message_id (``int``, *optional*):
|
||||
If the message is a reply, ID of the original message.
|
||||
|
||||
Returns:
|
||||
On success, a :obj:`Messages <pyrogram.Messages>` object is returned containing all the
|
||||
single messages sent.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
multi_media = []
|
||||
|
||||
@@ -65,14 +73,21 @@ class SendMediaGroup(BaseClient):
|
||||
|
||||
if isinstance(i, pyrogram.InputMediaPhoto):
|
||||
if os.path.exists(i.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedPhoto(
|
||||
file=self.save_file(i.media)
|
||||
while True:
|
||||
try:
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedPhoto(
|
||||
file=self.save_file(i.media)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
time.sleep(e.x)
|
||||
else:
|
||||
break
|
||||
|
||||
media = types.InputMediaPhoto(
|
||||
id=types.InputPhoto(
|
||||
@@ -106,25 +121,32 @@ class SendMediaGroup(BaseClient):
|
||||
)
|
||||
elif isinstance(i, pyrogram.InputMediaVideo):
|
||||
if os.path.exists(i.media):
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
file=self.save_file(i.media),
|
||||
thumb=None if i.thumb is None else self.save_file(i.thumb),
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
supports_streaming=i.supports_streaming or None,
|
||||
duration=i.duration,
|
||||
w=i.width,
|
||||
h=i.height
|
||||
),
|
||||
types.DocumentAttributeFilename(os.path.basename(i.media))
|
||||
]
|
||||
while True:
|
||||
try:
|
||||
media = self.send(
|
||||
functions.messages.UploadMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
media=types.InputMediaUploadedDocument(
|
||||
file=self.save_file(i.media),
|
||||
thumb=None if i.thumb is None else self.save_file(i.thumb),
|
||||
mime_type="video/mp4",
|
||||
attributes=[
|
||||
types.DocumentAttributeVideo(
|
||||
supports_streaming=i.supports_streaming or None,
|
||||
duration=i.duration,
|
||||
w=i.width,
|
||||
h=i.height
|
||||
),
|
||||
types.DocumentAttributeFilename(os.path.basename(i.media))
|
||||
]
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
time.sleep(e.x)
|
||||
else:
|
||||
break
|
||||
|
||||
media = types.InputMediaDocument(
|
||||
id=types.InputDocument(
|
||||
@@ -165,11 +187,30 @@ class SendMediaGroup(BaseClient):
|
||||
)
|
||||
)
|
||||
|
||||
return self.send(
|
||||
functions.messages.SendMultiMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
multi_media=multi_media,
|
||||
silent=disable_notification or None,
|
||||
reply_to_msg_id=reply_to_message_id
|
||||
while True:
|
||||
try:
|
||||
r = self.send(
|
||||
functions.messages.SendMultiMedia(
|
||||
peer=self.resolve_peer(chat_id),
|
||||
multi_media=multi_media,
|
||||
silent=disable_notification or None,
|
||||
reply_to_msg_id=reply_to_message_id
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
log.warning("Sleeping for {}s".format(e.x))
|
||||
time.sleep(e.x)
|
||||
else:
|
||||
break
|
||||
|
||||
return pyrogram.Messages._parse(
|
||||
self,
|
||||
types.messages.Messages(
|
||||
messages=[m.message for m in filter(
|
||||
lambda u: isinstance(u, (types.UpdateNewMessage, types.UpdateNewChannelMessage)),
|
||||
r.updates
|
||||
)],
|
||||
users=r.users,
|
||||
chats=r.chats
|
||||
)
|
||||
)
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -136,7 +135,7 @@ class SendVideo(BaseClient):
|
||||
thumb = None if thumb is None else self.save_file(thumb)
|
||||
file = self.save_file(video, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
mime_type="video/mp4",
|
||||
file=file,
|
||||
thumb=thumb,
|
||||
attributes=[
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -117,7 +116,7 @@ class SendVideoNote(BaseClient):
|
||||
thumb = None if thumb is None else self.save_file(thumb)
|
||||
file = self.save_file(video_note, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map[".mp4"],
|
||||
mime_type="video/mp4",
|
||||
file=file,
|
||||
thumb=thumb,
|
||||
attributes=[
|
||||
|
@@ -17,7 +17,6 @@
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import binascii
|
||||
import mimetypes
|
||||
import os
|
||||
import struct
|
||||
from typing import Union
|
||||
@@ -116,7 +115,7 @@ class SendVoice(BaseClient):
|
||||
if os.path.exists(voice):
|
||||
file = self.save_file(voice, progress=progress, progress_args=progress_args)
|
||||
media = types.InputMediaUploadedDocument(
|
||||
mime_type=mimetypes.types_map.get("." + voice.split(".")[-1], "audio/mpeg"),
|
||||
mime_type="audio/mpeg",
|
||||
file=file,
|
||||
attributes=[
|
||||
types.DocumentAttributeAudio(
|
||||
|
@@ -21,6 +21,7 @@ from .get_me import GetMe
|
||||
from .get_user_profile_photos import GetUserProfilePhotos
|
||||
from .get_users import GetUsers
|
||||
from .set_user_profile_photo import SetUserProfilePhoto
|
||||
from .update_username import UpdateUsername
|
||||
|
||||
|
||||
class Users(
|
||||
@@ -28,6 +29,7 @@ class Users(
|
||||
SetUserProfilePhoto,
|
||||
DeleteUserProfilePhotos,
|
||||
GetUsers,
|
||||
GetMe
|
||||
GetMe,
|
||||
UpdateUsername
|
||||
):
|
||||
pass
|
||||
|
51
pyrogram/client/methods/users/update_username.py
Normal file
51
pyrogram/client/methods/users/update_username.py
Normal file
@@ -0,0 +1,51 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 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 typing import Union
|
||||
|
||||
from pyrogram.api import functions
|
||||
from ...ext import BaseClient
|
||||
|
||||
|
||||
class UpdateUsername(BaseClient):
|
||||
def update_username(self,
|
||||
username: Union[str, None]) -> bool:
|
||||
"""Use this method to update your own username.
|
||||
|
||||
This method only works for users, not bots. Bot usernames must be changed via Bot Support or by recreating
|
||||
them from scratch using BotFather. To update a channel or supergroup username you can use
|
||||
:meth:`update_chat_username`.
|
||||
|
||||
Args:
|
||||
username (``str`` | ``None``):
|
||||
Username to set. "" (empty string) or None to remove the username.
|
||||
|
||||
Returns:
|
||||
True on success.
|
||||
|
||||
Raises:
|
||||
:class:`Error <pyrogram.Error>` in case of a Telegram RPC error.
|
||||
"""
|
||||
|
||||
return bool(
|
||||
self.send(
|
||||
functions.account.UpdateUsername(
|
||||
username=username or ""
|
||||
)
|
||||
)
|
||||
)
|
@@ -30,7 +30,7 @@ from .messages_and_media import (
|
||||
Sticker, Venue, Video, VideoNote, Voice, UserProfilePhotos,
|
||||
Message, Messages, MessageEntity, Poll, PollOption, Game
|
||||
)
|
||||
from .update import StopPropagation
|
||||
from .update import StopPropagation, ContinuePropagation
|
||||
from .user_and_chats import (
|
||||
Chat, ChatMember, ChatMembers, ChatPhoto,
|
||||
Dialog, Dialogs, User, UserStatus, ChatPreview, ChatPermissions
|
||||
|
@@ -40,15 +40,15 @@ class CallbackQuery(PyrogramType, Update):
|
||||
Sender.
|
||||
|
||||
chat_instance (``str``, *optional*):
|
||||
Global identifier, uniquely corresponding to the chat to which the message with the callback button was
|
||||
sent. Useful for high scores in games.
|
||||
|
||||
message (:obj:`Message <pyrogram.Message>`, *optional*):
|
||||
Message with the callback button that originated the query. Note that message content and message date will
|
||||
not be available if the message is too old.
|
||||
|
||||
message (:obj:`Message <pyrogram.Message>`, *optional*):
|
||||
Identifier of the message sent via the bot in inline mode, that originated the query.
|
||||
|
||||
inline_message_id (``str``):
|
||||
Global identifier, uniquely corresponding to the chat to which the message with the callback button was
|
||||
sent. Useful for high scores in games.
|
||||
Identifier of the message sent via the bot in inline mode, that originated the query.
|
||||
|
||||
data (``bytes``, *optional*):
|
||||
Data associated with the callback button. Be aware that a bad client can send arbitrary data in this field.
|
||||
@@ -72,9 +72,9 @@ class CallbackQuery(PyrogramType, Update):
|
||||
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
self.chat_instance = chat_instance
|
||||
self.message = message
|
||||
self.inline_message_id = inline_message_id
|
||||
self.chat_instance = chat_instance
|
||||
self.data = data
|
||||
self.game_short_name = game_short_name
|
||||
|
||||
|
@@ -63,7 +63,7 @@ class InlineKeyboardButton(PyrogramType):
|
||||
callback_game: CallbackGame = None):
|
||||
super().__init__(None)
|
||||
|
||||
self.text = text
|
||||
self.text = str(text)
|
||||
self.url = url
|
||||
self.callback_data = callback_data
|
||||
self.switch_inline_query = switch_inline_query
|
||||
|
@@ -46,7 +46,7 @@ class KeyboardButton(PyrogramType):
|
||||
request_location: bool = None):
|
||||
super().__init__(None)
|
||||
|
||||
self.text = text
|
||||
self.text = str(text)
|
||||
self.request_contact = request_contact
|
||||
self.request_location = request_location
|
||||
|
||||
|
@@ -21,6 +21,13 @@ class StopPropagation(StopIteration):
|
||||
pass
|
||||
|
||||
|
||||
class ContinuePropagation(StopIteration):
|
||||
pass
|
||||
|
||||
|
||||
class Update:
|
||||
def stop_propagation(self):
|
||||
raise StopPropagation
|
||||
|
||||
def continue_propagation(self):
|
||||
raise ContinuePropagation
|
||||
|
@@ -209,3 +209,14 @@ class Chat(PyrogramType):
|
||||
parsed_chat.invite_link = full_chat.exported_invite.link
|
||||
|
||||
return parsed_chat
|
||||
|
||||
@staticmethod
|
||||
def _parse_chat(client, chat):
|
||||
# A wrapper around each entity parser: User, Chat and Channel.
|
||||
# Currently unused, might become useful in future.
|
||||
if isinstance(chat, types.Chat):
|
||||
return Chat._parse_chat_chat(client, chat)
|
||||
elif isinstance(chat, types.User):
|
||||
return Chat._parse_user_chat(client, chat)
|
||||
else:
|
||||
return Chat._parse_channel_chat(client, chat)
|
||||
|
19
pyrogram/vendor/__init__.py
vendored
Normal file
19
pyrogram/vendor/__init__.py
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 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 .typing import typing
|
17
pyrogram/vendor/typing/__init__.py
vendored
Normal file
17
pyrogram/vendor/typing/__init__.py
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-2019 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/>.
|
2413
pyrogram/vendor/typing/typing.py
vendored
Normal file
2413
pyrogram/vendor/typing/typing.py
vendored
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user