mirror of
https://github.com/pyrogram/pyrogram
synced 2025-08-29 13:27:47 +00:00
Merge branch 'mixin' into develop
# Conflicts: # pyrogram/client/client.py
This commit is contained in:
commit
3419b0b98e
@ -4,6 +4,7 @@ Client
|
|||||||
.. currentmodule:::: pyrogram.Client
|
.. currentmodule:::: pyrogram.Client
|
||||||
|
|
||||||
.. autoclass:: pyrogram.Client
|
.. autoclass:: pyrogram.Client
|
||||||
|
:inherited-members:
|
||||||
:members:
|
:members:
|
||||||
|
|
||||||
**Available methods**
|
**Available methods**
|
||||||
@ -49,9 +50,12 @@ Client
|
|||||||
change_cloud_password
|
change_cloud_password
|
||||||
remove_cloud_password
|
remove_cloud_password
|
||||||
add_contacts
|
add_contacts
|
||||||
|
get_contacts
|
||||||
delete_contacts
|
delete_contacts
|
||||||
get_inline_bot_results
|
get_inline_bot_results
|
||||||
send_inline_bot_result
|
send_inline_bot_result
|
||||||
|
answer_callback_query
|
||||||
get_users
|
get_users
|
||||||
|
get_chat
|
||||||
get_messages
|
get_messages
|
||||||
answer_callback_query
|
get_history
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
"""This example shows how to handle callback queries, i.e.: queries coming from inline button presses.
|
"""This example shows how to handle callback queries, i.e.: queries coming from inline button presses.
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client, Filters
|
from pyrogram import Client, Filters
|
||||||
|
|
||||||
"""This simple echo bot replies to every private text message.
|
"""This simple echo bot replies to every private text message.
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 time
|
import time
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 time
|
import time
|
||||||
|
|
||||||
from pyrogram import Client
|
from pyrogram import Client
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 time
|
import time
|
||||||
from string import ascii_lowercase
|
from string import ascii_lowercase
|
||||||
|
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
"""This example demonstrates a basic API usage"""
|
"""This example demonstrates a basic API usage"""
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
"""This example shows how to query an inline bot"""
|
"""This example shows how to query an inline bot"""
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client
|
from pyrogram import Client
|
||||||
|
|
||||||
"""This example shows how to handle raw updates"""
|
"""This example shows how to handle raw updates"""
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
|
from pyrogram import Client, ReplyKeyboardMarkup, InlineKeyboardMarkup, InlineKeyboardButton
|
||||||
|
|
||||||
"""This example will show you how to send normal and inline keyboards.
|
"""This example will show you how to send normal and inline keyboards.
|
||||||
|
@ -1,3 +1,21 @@
|
|||||||
|
# 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 import Client, Emoji, Filters
|
from pyrogram import Client, Emoji, Filters
|
||||||
|
|
||||||
"""This is the Welcome Bot in @PyrogramChat.
|
"""This is the Welcome Bot in @PyrogramChat.
|
||||||
|
@ -16,9 +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 .chat_action import ChatAction
|
|
||||||
from .client import Client
|
from .client import Client
|
||||||
from .emoji import Emoji
|
from .ext import BaseClient, ChatAction, Emoji, ParseMode
|
||||||
from .filters import Filters
|
from .filters import Filters
|
||||||
from .handlers import MessageHandler, CallbackQueryHandler, RawUpdateHandler
|
from .handlers import MessageHandler, CallbackQueryHandler, RawUpdateHandler
|
||||||
from .parse_mode import ParseMode
|
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,7 +24,7 @@ from threading import Thread
|
|||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram.api import types
|
from pyrogram.api import types
|
||||||
from .. import utils
|
from ..ext import utils
|
||||||
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler
|
from ..handlers import RawUpdateHandler, CallbackQueryHandler, MessageHandler
|
||||||
|
|
||||||
log = logging.getLogger(__name__)
|
log = logging.getLogger(__name__)
|
||||||
@ -138,14 +138,7 @@ class Dispatcher:
|
|||||||
self.dispatch(update, users=users, chats=chats, is_raw=True)
|
self.dispatch(update, users=users, chats=chats, is_raw=True)
|
||||||
|
|
||||||
if isinstance(update, Dispatcher.MESSAGE_UPDATES):
|
if isinstance(update, Dispatcher.MESSAGE_UPDATES):
|
||||||
if isinstance(update.message, types.Message):
|
message = utils.parse_messages(
|
||||||
parser = utils.parse_message
|
|
||||||
elif isinstance(update.message, types.MessageService):
|
|
||||||
parser = utils.parse_message_service
|
|
||||||
else:
|
|
||||||
continue
|
|
||||||
|
|
||||||
message = parser(
|
|
||||||
self.client,
|
self.client,
|
||||||
update.message,
|
update.message,
|
||||||
users,
|
users,
|
||||||
|
23
pyrogram/client/ext/__init__.py
Normal file
23
pyrogram/client/ext/__init__.py
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
# 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 .base_client import BaseClient
|
||||||
|
from .chat_action import ChatAction
|
||||||
|
from .emoji import Emoji
|
||||||
|
from .parse_mode import ParseMode
|
||||||
|
from .syncer import Syncer
|
103
pyrogram/client/ext/base_client.py
Normal file
103
pyrogram/client/ext/base_client.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# 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 re
|
||||||
|
from queue import Queue
|
||||||
|
from threading import Lock
|
||||||
|
|
||||||
|
from ..style import Markdown, HTML
|
||||||
|
from ...api.core import Object
|
||||||
|
from ...session.internals import MsgId
|
||||||
|
|
||||||
|
|
||||||
|
class BaseClient:
|
||||||
|
INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:t\.me/joinchat/)([\w-]+)$")
|
||||||
|
BOT_TOKEN_RE = re.compile(r"^\d+:[\w-]+$")
|
||||||
|
DIALOGS_AT_ONCE = 100
|
||||||
|
UPDATES_WORKERS = 1
|
||||||
|
DOWNLOAD_WORKERS = 1
|
||||||
|
OFFLINE_SLEEP = 300
|
||||||
|
|
||||||
|
MEDIA_TYPE_ID = {
|
||||||
|
0: "thumbnail",
|
||||||
|
1: "thumbnail",
|
||||||
|
2: "photo",
|
||||||
|
3: "voice",
|
||||||
|
4: "video",
|
||||||
|
5: "document",
|
||||||
|
8: "sticker",
|
||||||
|
9: "audio",
|
||||||
|
10: "gif",
|
||||||
|
13: "video_note"
|
||||||
|
}
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.token = None
|
||||||
|
self.dc_id = None
|
||||||
|
self.auth_key = None
|
||||||
|
self.user_id = None
|
||||||
|
self.date = None
|
||||||
|
|
||||||
|
self.rnd_id = MsgId
|
||||||
|
self.channels_pts = {}
|
||||||
|
|
||||||
|
self.peers_by_id = {}
|
||||||
|
self.peers_by_username = {}
|
||||||
|
self.peers_by_phone = {}
|
||||||
|
|
||||||
|
self.markdown = Markdown(self.peers_by_id)
|
||||||
|
self.html = HTML(self.peers_by_id)
|
||||||
|
|
||||||
|
self.session = None
|
||||||
|
self.media_sessions = {}
|
||||||
|
self.media_sessions_lock = Lock()
|
||||||
|
|
||||||
|
self.is_started = None
|
||||||
|
self.is_idle = None
|
||||||
|
|
||||||
|
self.updates_queue = Queue()
|
||||||
|
self.updates_workers_list = []
|
||||||
|
self.download_queue = Queue()
|
||||||
|
self.download_workers_list = []
|
||||||
|
|
||||||
|
def send(self, data: Object):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def resolve_peer(self, peer_id: int or str):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def add_handler(self, handler, group: int = 0) -> tuple:
|
||||||
|
pass
|
||||||
|
|
||||||
|
def save_file(
|
||||||
|
self,
|
||||||
|
path: str,
|
||||||
|
file_id: int = None,
|
||||||
|
file_part: int = 0,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()
|
||||||
|
):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def get_messages(
|
||||||
|
self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_ids,
|
||||||
|
replies: int = 1
|
||||||
|
):
|
||||||
|
pass
|
808
pyrogram/client/ext/utils.py
Normal file
808
pyrogram/client/ext/utils.py
Normal file
@ -0,0 +1,808 @@
|
|||||||
|
# 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 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
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# TODO: Organize the code better?
|
||||||
|
|
||||||
|
ENTITIES = {
|
||||||
|
types.MessageEntityMention.ID: "mention",
|
||||||
|
types.MessageEntityHashtag.ID: "hashtag",
|
||||||
|
types.MessageEntityBotCommand.ID: "bot_command",
|
||||||
|
types.MessageEntityUrl.ID: "url",
|
||||||
|
types.MessageEntityEmail.ID: "email",
|
||||||
|
types.MessageEntityBold.ID: "bold",
|
||||||
|
types.MessageEntityItalic.ID: "italic",
|
||||||
|
types.MessageEntityCode.ID: "code",
|
||||||
|
types.MessageEntityPre.ID: "pre",
|
||||||
|
types.MessageEntityTextUrl.ID: "text_link",
|
||||||
|
types.MessageEntityMentionName.ID: "text_mention"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
def parse_entities(entities: list, users: dict) -> list:
|
||||||
|
output_entities = []
|
||||||
|
|
||||||
|
for entity in entities:
|
||||||
|
entity_type = ENTITIES.get(entity.ID, None)
|
||||||
|
|
||||||
|
if entity_type:
|
||||||
|
output_entities.append(pyrogram_types.MessageEntity(
|
||||||
|
type=entity_type,
|
||||||
|
offset=entity.offset,
|
||||||
|
length=entity.length,
|
||||||
|
url=getattr(entity, "url", None),
|
||||||
|
user=parse_user(
|
||||||
|
users.get(
|
||||||
|
getattr(entity, "user_id", None),
|
||||||
|
None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
|
||||||
|
return output_entities
|
||||||
|
|
||||||
|
|
||||||
|
def parse_chat_photo(photo):
|
||||||
|
if not isinstance(photo, (types.UserProfilePhoto, types.ChatPhoto)):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not isinstance(photo.photo_small, types.FileLocation):
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not isinstance(photo.photo_big, types.FileLocation):
|
||||||
|
return None
|
||||||
|
|
||||||
|
photo_id = getattr(photo, "photo_id", 0)
|
||||||
|
loc_small = photo.photo_small
|
||||||
|
loc_big = photo.photo_big
|
||||||
|
|
||||||
|
return pyrogram_types.ChatPhoto(
|
||||||
|
small_file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi", 1, loc_small.dc_id, photo_id, 0, loc_small.volume_id,
|
||||||
|
loc_small.secret, loc_small.local_id
|
||||||
|
)
|
||||||
|
),
|
||||||
|
big_file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi", 1, loc_big.dc_id, photo_id, 0, loc_big.volume_id,
|
||||||
|
loc_big.secret, loc_big.local_id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_user(user: types.User) -> pyrogram_types.User or None:
|
||||||
|
return pyrogram_types.User(
|
||||||
|
id=user.id,
|
||||||
|
is_bot=user.bot,
|
||||||
|
first_name=user.first_name,
|
||||||
|
last_name=user.last_name,
|
||||||
|
username=user.username,
|
||||||
|
language_code=user.lang_code,
|
||||||
|
phone_number=user.phone,
|
||||||
|
photo=parse_chat_photo(user.photo)
|
||||||
|
) if user else None
|
||||||
|
|
||||||
|
|
||||||
|
def parse_chat(message: types.Message, users: dict, chats: dict) -> pyrogram_types.Chat:
|
||||||
|
if isinstance(message.to_id, types.PeerUser):
|
||||||
|
return parse_user_chat(users[message.to_id.user_id if message.out else message.from_id])
|
||||||
|
elif isinstance(message.to_id, types.PeerChat):
|
||||||
|
return parse_chat_chat(chats[message.to_id.chat_id])
|
||||||
|
else:
|
||||||
|
return parse_channel_chat(chats[message.to_id.channel_id])
|
||||||
|
|
||||||
|
|
||||||
|
def parse_user_chat(user: types.User) -> pyrogram_types.Chat:
|
||||||
|
return pyrogram_types.Chat(
|
||||||
|
id=user.id,
|
||||||
|
type="private",
|
||||||
|
username=user.username,
|
||||||
|
first_name=user.first_name,
|
||||||
|
last_name=user.last_name,
|
||||||
|
photo=parse_chat_photo(user.photo)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_chat_chat(chat: types.Chat) -> pyrogram_types.Chat:
|
||||||
|
admins_enabled = getattr(chat, "admins_enabled", None)
|
||||||
|
|
||||||
|
if admins_enabled is not None:
|
||||||
|
admins_enabled = not admins_enabled
|
||||||
|
|
||||||
|
return pyrogram_types.Chat(
|
||||||
|
id=-chat.id,
|
||||||
|
type="group",
|
||||||
|
title=chat.title,
|
||||||
|
all_members_are_administrators=admins_enabled,
|
||||||
|
photo=parse_chat_photo(getattr(chat, "photo", None))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_channel_chat(channel: types.Channel) -> pyrogram_types.Chat:
|
||||||
|
return pyrogram_types.Chat(
|
||||||
|
id=int("-100" + str(channel.id)),
|
||||||
|
type="supergroup" if channel.megagroup else "channel",
|
||||||
|
title=channel.title,
|
||||||
|
username=getattr(channel, "username", None),
|
||||||
|
photo=parse_chat_photo(getattr(channel, "photo", None))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_thumb(thumb: types.PhotoSize or types.PhotoCachedSize) -> pyrogram_types.PhotoSize or None:
|
||||||
|
if isinstance(thumb, (types.PhotoSize, types.PhotoCachedSize)):
|
||||||
|
loc = thumb.location
|
||||||
|
|
||||||
|
if isinstance(thumb, types.PhotoSize):
|
||||||
|
file_size = thumb.size
|
||||||
|
else:
|
||||||
|
file_size = len(thumb.bytes)
|
||||||
|
|
||||||
|
if isinstance(loc, types.FileLocation):
|
||||||
|
return pyrogram_types.PhotoSize(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi",
|
||||||
|
0,
|
||||||
|
loc.dc_id,
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
loc.volume_id,
|
||||||
|
loc.secret,
|
||||||
|
loc.local_id
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=thumb.w,
|
||||||
|
height=thumb.h,
|
||||||
|
file_size=file_size
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def decode(s: str) -> bytes:
|
||||||
|
s = b64decode(s + "=" * (-len(s) % 4), "-_")
|
||||||
|
r = b""
|
||||||
|
|
||||||
|
assert s[-1] == 2
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(s) - 1:
|
||||||
|
if s[i] != 0:
|
||||||
|
r += bytes([s[i]])
|
||||||
|
else:
|
||||||
|
r += b"\x00" * s[i + 1]
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def encode(s: bytes) -> str:
|
||||||
|
r = b""
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
for i in s + bytes([2]):
|
||||||
|
if i == 0:
|
||||||
|
n += 1
|
||||||
|
else:
|
||||||
|
if n:
|
||||||
|
r += b"\x00" + bytes([n])
|
||||||
|
n = 0
|
||||||
|
|
||||||
|
r += bytes([i])
|
||||||
|
|
||||||
|
return b64encode(r, b"-_").decode().rstrip("=")
|
||||||
|
|
||||||
|
|
||||||
|
# TODO: Reorganize code, maybe split parts as well
|
||||||
|
def parse_messages(
|
||||||
|
client,
|
||||||
|
messages: list or types.Message or types.MessageService or types.MessageEmpty,
|
||||||
|
users: dict,
|
||||||
|
chats: dict,
|
||||||
|
replies: int = 1
|
||||||
|
) -> pyrogram_types.Message:
|
||||||
|
is_list = isinstance(messages, list)
|
||||||
|
messages = messages if is_list else [messages]
|
||||||
|
parsed_messages = []
|
||||||
|
|
||||||
|
for message in messages:
|
||||||
|
if isinstance(message, types.Message):
|
||||||
|
entities = parse_entities(message.entities, users)
|
||||||
|
|
||||||
|
forward_from = None
|
||||||
|
forward_from_chat = None
|
||||||
|
forward_from_message_id = None
|
||||||
|
forward_signature = None
|
||||||
|
forward_date = None
|
||||||
|
|
||||||
|
forward_header = message.fwd_from # type: types.MessageFwdHeader
|
||||||
|
|
||||||
|
if forward_header:
|
||||||
|
forward_date = forward_header.date
|
||||||
|
|
||||||
|
if forward_header.from_id:
|
||||||
|
forward_from = parse_user(users[forward_header.from_id])
|
||||||
|
else:
|
||||||
|
forward_from_chat = parse_channel_chat(chats[forward_header.channel_id])
|
||||||
|
forward_from_message_id = forward_header.channel_post
|
||||||
|
forward_signature = forward_header.post_author
|
||||||
|
|
||||||
|
photo = None
|
||||||
|
location = None
|
||||||
|
contact = None
|
||||||
|
venue = None
|
||||||
|
audio = None
|
||||||
|
voice = None
|
||||||
|
video = None
|
||||||
|
video_note = None
|
||||||
|
sticker = None
|
||||||
|
document = None
|
||||||
|
|
||||||
|
media = message.media
|
||||||
|
|
||||||
|
if media:
|
||||||
|
if isinstance(media, types.MessageMediaPhoto):
|
||||||
|
photo = media.photo
|
||||||
|
|
||||||
|
if isinstance(photo, types.Photo):
|
||||||
|
sizes = photo.sizes
|
||||||
|
photo_sizes = []
|
||||||
|
|
||||||
|
for size in sizes:
|
||||||
|
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
||||||
|
loc = size.location
|
||||||
|
|
||||||
|
if isinstance(size, types.PhotoSize):
|
||||||
|
file_size = size.size
|
||||||
|
else:
|
||||||
|
file_size = len(size.bytes)
|
||||||
|
|
||||||
|
if isinstance(loc, types.FileLocation):
|
||||||
|
photo_size = pyrogram_types.PhotoSize(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi",
|
||||||
|
2,
|
||||||
|
loc.dc_id,
|
||||||
|
photo.id,
|
||||||
|
photo.access_hash,
|
||||||
|
loc.volume_id,
|
||||||
|
loc.secret,
|
||||||
|
loc.local_id
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=size.w,
|
||||||
|
height=size.h,
|
||||||
|
file_size=file_size,
|
||||||
|
date=photo.date
|
||||||
|
)
|
||||||
|
|
||||||
|
photo_sizes.append(photo_size)
|
||||||
|
|
||||||
|
photo = photo_sizes
|
||||||
|
elif isinstance(media, types.MessageMediaGeo):
|
||||||
|
geo_point = media.geo
|
||||||
|
|
||||||
|
if isinstance(geo_point, types.GeoPoint):
|
||||||
|
location = pyrogram_types.Location(
|
||||||
|
longitude=geo_point.long,
|
||||||
|
latitude=geo_point.lat
|
||||||
|
)
|
||||||
|
elif isinstance(media, types.MessageMediaContact):
|
||||||
|
contact = pyrogram_types.Contact(
|
||||||
|
phone_number=media.phone_number,
|
||||||
|
first_name=media.first_name,
|
||||||
|
last_name=media.last_name or None,
|
||||||
|
user_id=media.user_id or None
|
||||||
|
)
|
||||||
|
elif isinstance(media, types.MessageMediaVenue):
|
||||||
|
venue = pyrogram_types.Venue(
|
||||||
|
location=pyrogram_types.Location(
|
||||||
|
longitude=media.geo.long,
|
||||||
|
latitude=media.geo.lat
|
||||||
|
),
|
||||||
|
title=media.title,
|
||||||
|
address=media.address,
|
||||||
|
foursquare_id=media.venue_id or None
|
||||||
|
)
|
||||||
|
elif isinstance(media, types.MessageMediaDocument):
|
||||||
|
doc = media.document
|
||||||
|
|
||||||
|
if isinstance(doc, types.Document):
|
||||||
|
attributes = {type(i): i for i in doc.attributes}
|
||||||
|
|
||||||
|
file_name = getattr(
|
||||||
|
attributes.get(
|
||||||
|
types.DocumentAttributeFilename, None
|
||||||
|
), "file_name", None
|
||||||
|
)
|
||||||
|
|
||||||
|
if types.DocumentAttributeAudio in attributes:
|
||||||
|
audio_attributes = attributes[types.DocumentAttributeAudio]
|
||||||
|
|
||||||
|
if audio_attributes.voice:
|
||||||
|
voice = pyrogram_types.Voice(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
3,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
duration=audio_attributes.duration,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_size=doc.size,
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
file_name=file_name,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
audio = pyrogram_types.Audio(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
9,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
duration=audio_attributes.duration,
|
||||||
|
performer=audio_attributes.performer,
|
||||||
|
title=audio_attributes.title,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_size=doc.size,
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
file_name=file_name,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
elif types.DocumentAttributeAnimated in attributes:
|
||||||
|
document = pyrogram_types.Document(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
10,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
file_name=file_name,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_size=doc.size,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
elif types.DocumentAttributeVideo in attributes:
|
||||||
|
video_attributes = attributes[types.DocumentAttributeVideo]
|
||||||
|
|
||||||
|
if video_attributes.round_message:
|
||||||
|
video_note = pyrogram_types.VideoNote(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
13,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
length=video_attributes.w,
|
||||||
|
duration=video_attributes.duration,
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
file_size=doc.size,
|
||||||
|
file_name=file_name,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
video = pyrogram_types.Video(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
4,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=video_attributes.w,
|
||||||
|
height=video_attributes.h,
|
||||||
|
duration=video_attributes.duration,
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_size=doc.size,
|
||||||
|
file_name=file_name,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
elif types.DocumentAttributeSticker in attributes:
|
||||||
|
image_size_attributes = attributes.get(types.DocumentAttributeImageSize, None)
|
||||||
|
sticker_attribute = attributes[types.DocumentAttributeSticker]
|
||||||
|
|
||||||
|
if isinstance(sticker_attribute.stickerset, types.InputStickerSetID):
|
||||||
|
try:
|
||||||
|
set_name = client.send(
|
||||||
|
functions.messages.GetStickerSet(sticker_attribute.stickerset)
|
||||||
|
).set.short_name
|
||||||
|
except StickersetInvalid:
|
||||||
|
set_name = None
|
||||||
|
else:
|
||||||
|
set_name = None
|
||||||
|
|
||||||
|
sticker = pyrogram_types.Sticker(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
8,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=image_size_attributes.w if image_size_attributes else 0,
|
||||||
|
height=image_size_attributes.h if image_size_attributes else 0,
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
# TODO: mask_position
|
||||||
|
set_name=set_name,
|
||||||
|
emoji=sticker_attribute.alt or None,
|
||||||
|
file_size=doc.size,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_name=file_name,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
document = pyrogram_types.Document(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqq",
|
||||||
|
5,
|
||||||
|
doc.dc_id,
|
||||||
|
doc.id,
|
||||||
|
doc.access_hash
|
||||||
|
)
|
||||||
|
),
|
||||||
|
thumb=parse_thumb(doc.thumb),
|
||||||
|
file_name=file_name,
|
||||||
|
mime_type=doc.mime_type,
|
||||||
|
file_size=doc.size,
|
||||||
|
date=doc.date
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
media = None
|
||||||
|
|
||||||
|
reply_markup = message.reply_markup
|
||||||
|
|
||||||
|
if reply_markup:
|
||||||
|
if isinstance(reply_markup, types.ReplyKeyboardForceReply):
|
||||||
|
reply_markup = pyrogram_types.ForceReply.read(reply_markup)
|
||||||
|
elif isinstance(reply_markup, types.ReplyKeyboardMarkup):
|
||||||
|
reply_markup = pyrogram_types.ReplyKeyboardMarkup.read(reply_markup)
|
||||||
|
elif isinstance(reply_markup, types.ReplyInlineMarkup):
|
||||||
|
reply_markup = pyrogram_types.InlineKeyboardMarkup.read(reply_markup)
|
||||||
|
elif isinstance(reply_markup, types.ReplyKeyboardHide):
|
||||||
|
reply_markup = pyrogram_types.ReplyKeyboardRemove.read(reply_markup)
|
||||||
|
else:
|
||||||
|
reply_markup = None
|
||||||
|
|
||||||
|
m = pyrogram_types.Message(
|
||||||
|
message_id=message.id,
|
||||||
|
date=message.date,
|
||||||
|
chat=parse_chat(message, users, chats),
|
||||||
|
from_user=parse_user(users.get(message.from_id, None)),
|
||||||
|
text=message.message or None if media is None else None,
|
||||||
|
caption=message.message or None if media is not None else None,
|
||||||
|
entities=entities or None if media is None else None,
|
||||||
|
caption_entities=entities or None if media is not None else None,
|
||||||
|
author_signature=message.post_author,
|
||||||
|
forward_from=forward_from,
|
||||||
|
forward_from_chat=forward_from_chat,
|
||||||
|
forward_from_message_id=forward_from_message_id,
|
||||||
|
forward_signature=forward_signature,
|
||||||
|
forward_date=forward_date,
|
||||||
|
edit_date=message.edit_date,
|
||||||
|
media_group_id=message.grouped_id,
|
||||||
|
photo=photo,
|
||||||
|
location=location,
|
||||||
|
contact=contact,
|
||||||
|
venue=venue,
|
||||||
|
audio=audio,
|
||||||
|
voice=voice,
|
||||||
|
video=video,
|
||||||
|
video_note=video_note,
|
||||||
|
sticker=sticker,
|
||||||
|
document=document,
|
||||||
|
views=message.views,
|
||||||
|
via_bot=parse_user(users.get(message.via_bot_id, None)),
|
||||||
|
outgoing=message.out,
|
||||||
|
client=proxy(client),
|
||||||
|
reply_markup=reply_markup
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
elif isinstance(message, types.MessageService):
|
||||||
|
action = message.action
|
||||||
|
|
||||||
|
new_chat_members = None
|
||||||
|
left_chat_member = None
|
||||||
|
new_chat_title = None
|
||||||
|
delete_chat_photo = None
|
||||||
|
migrate_to_chat_id = None
|
||||||
|
migrate_from_chat_id = None
|
||||||
|
group_chat_created = None
|
||||||
|
channel_chat_created = None
|
||||||
|
new_chat_photo = None
|
||||||
|
|
||||||
|
if isinstance(action, types.MessageActionChatAddUser):
|
||||||
|
new_chat_members = [parse_user(users[i]) for i in action.users]
|
||||||
|
elif isinstance(action, types.MessageActionChatJoinedByLink):
|
||||||
|
new_chat_members = [parse_user(users[message.from_id])]
|
||||||
|
elif isinstance(action, types.MessageActionChatDeleteUser):
|
||||||
|
left_chat_member = parse_user(users[action.user_id])
|
||||||
|
elif isinstance(action, types.MessageActionChatEditTitle):
|
||||||
|
new_chat_title = action.title
|
||||||
|
elif isinstance(action, types.MessageActionChatDeletePhoto):
|
||||||
|
delete_chat_photo = True
|
||||||
|
elif isinstance(action, types.MessageActionChatMigrateTo):
|
||||||
|
migrate_to_chat_id = action.channel_id
|
||||||
|
elif isinstance(action, types.MessageActionChannelMigrateFrom):
|
||||||
|
migrate_from_chat_id = action.chat_id
|
||||||
|
elif isinstance(action, types.MessageActionChatCreate):
|
||||||
|
group_chat_created = True
|
||||||
|
elif isinstance(action, types.MessageActionChannelCreate):
|
||||||
|
channel_chat_created = True
|
||||||
|
elif isinstance(action, types.MessageActionChatEditPhoto):
|
||||||
|
photo = action.photo
|
||||||
|
|
||||||
|
if isinstance(photo, types.Photo):
|
||||||
|
sizes = photo.sizes
|
||||||
|
photo_sizes = []
|
||||||
|
|
||||||
|
for size in sizes:
|
||||||
|
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
||||||
|
loc = size.location
|
||||||
|
|
||||||
|
if isinstance(size, types.PhotoSize):
|
||||||
|
file_size = size.size
|
||||||
|
else:
|
||||||
|
file_size = len(size.bytes)
|
||||||
|
|
||||||
|
if isinstance(loc, types.FileLocation):
|
||||||
|
photo_size = pyrogram_types.PhotoSize(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi",
|
||||||
|
2,
|
||||||
|
loc.dc_id,
|
||||||
|
photo.id,
|
||||||
|
photo.access_hash,
|
||||||
|
loc.volume_id,
|
||||||
|
loc.secret,
|
||||||
|
loc.local_id
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=size.w,
|
||||||
|
height=size.h,
|
||||||
|
file_size=file_size,
|
||||||
|
date=photo.date
|
||||||
|
)
|
||||||
|
|
||||||
|
photo_sizes.append(photo_size)
|
||||||
|
|
||||||
|
new_chat_photo = photo_sizes
|
||||||
|
|
||||||
|
m = pyrogram_types.Message(
|
||||||
|
message_id=message.id,
|
||||||
|
date=message.date,
|
||||||
|
chat=parse_chat(message, users, chats),
|
||||||
|
from_user=parse_user(users.get(message.from_id, None)),
|
||||||
|
new_chat_members=new_chat_members,
|
||||||
|
left_chat_member=left_chat_member,
|
||||||
|
new_chat_title=new_chat_title,
|
||||||
|
new_chat_photo=new_chat_photo,
|
||||||
|
delete_chat_photo=delete_chat_photo,
|
||||||
|
migrate_to_chat_id=int("-100" + str(migrate_to_chat_id)) if migrate_to_chat_id else None,
|
||||||
|
migrate_from_chat_id=-migrate_from_chat_id if migrate_from_chat_id else None,
|
||||||
|
group_chat_created=group_chat_created,
|
||||||
|
channel_chat_created=channel_chat_created,
|
||||||
|
client=proxy(client)
|
||||||
|
# TODO: supergroup_chat_created
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
else:
|
||||||
|
m = pyrogram_types.Message(message_id=message.id, client=proxy(client))
|
||||||
|
|
||||||
|
parsed_messages.append(m)
|
||||||
|
|
||||||
|
return parsed_messages if is_list else parsed_messages[0]
|
||||||
|
|
||||||
|
|
||||||
|
def get_peer_id(input_peer) -> int:
|
||||||
|
return (
|
||||||
|
input_peer.user_id if isinstance(input_peer, types.InputPeerUser)
|
||||||
|
else -input_peer.chat_id if isinstance(input_peer, types.InputPeerChat)
|
||||||
|
else int("-100" + str(input_peer.channel_id))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_input_peer(peer_id: int, access_hash: int):
|
||||||
|
return (
|
||||||
|
types.InputPeerUser(peer_id, access_hash) if peer_id > 0
|
||||||
|
else types.InputPeerChannel(int(str(peer_id)[4:]), access_hash)
|
||||||
|
if (str(peer_id).startswith("-100") and access_hash)
|
||||||
|
else types.InputPeerChat(-peer_id)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def get_offset_date(dialogs):
|
||||||
|
for m in reversed(dialogs.messages):
|
||||||
|
if isinstance(m, types.MessageEmpty):
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
return m.date
|
||||||
|
else:
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
def parse_photos(photos):
|
||||||
|
if isinstance(photos, types.photos.Photos):
|
||||||
|
total_count = len(photos.photos)
|
||||||
|
else:
|
||||||
|
total_count = photos.count
|
||||||
|
|
||||||
|
user_profile_photos = []
|
||||||
|
|
||||||
|
for photo in photos.photos:
|
||||||
|
if isinstance(photo, types.Photo):
|
||||||
|
sizes = photo.sizes
|
||||||
|
photo_sizes = []
|
||||||
|
|
||||||
|
for size in sizes:
|
||||||
|
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
||||||
|
loc = size.location
|
||||||
|
|
||||||
|
if isinstance(size, types.PhotoSize):
|
||||||
|
file_size = size.size
|
||||||
|
else:
|
||||||
|
file_size = len(size.bytes)
|
||||||
|
|
||||||
|
if isinstance(loc, types.FileLocation):
|
||||||
|
photo_size = pyrogram_types.PhotoSize(
|
||||||
|
file_id=encode(
|
||||||
|
pack(
|
||||||
|
"<iiqqqqi",
|
||||||
|
2,
|
||||||
|
loc.dc_id,
|
||||||
|
photo.id,
|
||||||
|
photo.access_hash,
|
||||||
|
loc.volume_id,
|
||||||
|
loc.secret,
|
||||||
|
loc.local_id
|
||||||
|
)
|
||||||
|
),
|
||||||
|
width=size.w,
|
||||||
|
height=size.h,
|
||||||
|
file_size=file_size,
|
||||||
|
date=photo.date
|
||||||
|
)
|
||||||
|
|
||||||
|
photo_sizes.append(photo_size)
|
||||||
|
|
||||||
|
user_profile_photos.append(photo_sizes)
|
||||||
|
|
||||||
|
return pyrogram_types.UserProfilePhotos(
|
||||||
|
total_count=total_count,
|
||||||
|
photos=user_profile_photos
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_callback_query(client, callback_query, users):
|
||||||
|
peer = callback_query.peer
|
||||||
|
|
||||||
|
if isinstance(peer, types.PeerUser):
|
||||||
|
peer_id = peer.user_id
|
||||||
|
elif isinstance(peer, types.PeerChat):
|
||||||
|
peer_id = -peer.chat_id
|
||||||
|
else:
|
||||||
|
peer_id = int("-100" + str(peer.channel_id))
|
||||||
|
|
||||||
|
return pyrogram_types.CallbackQuery(
|
||||||
|
id=callback_query.query_id,
|
||||||
|
from_user=parse_user(users[callback_query.user_id]),
|
||||||
|
message=client.get_messages(peer_id, callback_query.msg_id),
|
||||||
|
chat_instance=str(callback_query.chat_instance),
|
||||||
|
data=callback_query.data.decode(),
|
||||||
|
game_short_name=callback_query.game_short_name
|
||||||
|
# TODO: add inline_message_id
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def parse_chat_full(
|
||||||
|
client,
|
||||||
|
chat_full: types.messages.ChatFull or types.UserFull
|
||||||
|
) -> pyrogram_types.Chat:
|
||||||
|
if isinstance(chat_full, types.UserFull):
|
||||||
|
chat = parse_user_chat(chat_full.user)
|
||||||
|
chat.description = chat_full.about
|
||||||
|
else:
|
||||||
|
full_chat = chat_full.full_chat
|
||||||
|
chat = None
|
||||||
|
|
||||||
|
for i in chat_full.chats:
|
||||||
|
if full_chat.id == i.id:
|
||||||
|
chat = i
|
||||||
|
|
||||||
|
if isinstance(full_chat, types.ChatFull):
|
||||||
|
chat = parse_chat_chat(chat)
|
||||||
|
else:
|
||||||
|
chat = parse_channel_chat(chat)
|
||||||
|
chat.description = full_chat.about or None
|
||||||
|
# TODO: Add StickerSet type
|
||||||
|
chat.can_set_sticker_set = full_chat.can_set_stickers
|
||||||
|
chat.sticker_set_name = full_chat.stickerset
|
||||||
|
|
||||||
|
if full_chat.pinned_msg_id:
|
||||||
|
chat.pinned_message = client.get_messages(
|
||||||
|
int("-100" + str(full_chat.id)),
|
||||||
|
full_chat.pinned_msg_id
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
|
||||||
|
chat.invite_link = full_chat.exported_invite.link
|
||||||
|
|
||||||
|
return chat
|
@ -32,6 +32,9 @@ class Filters:
|
|||||||
"""This class provides access to all Filters available in Pyrogram.
|
"""This class provides access to all Filters available in Pyrogram.
|
||||||
Filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`."""
|
Filters are intended to be used with the :obj:`MessageHandler <pyrogram.MessageHandler>`."""
|
||||||
|
|
||||||
|
bot = build("Bot", lambda _, m: bool(m.from_user and m.from_user.is_bot))
|
||||||
|
"""Filter messages coming from bots"""
|
||||||
|
|
||||||
incoming = build("Incoming", lambda _, m: not m.outgoing)
|
incoming = build("Incoming", lambda _, m: not m.outgoing)
|
||||||
"""Filter incoming messages."""
|
"""Filter incoming messages."""
|
||||||
|
|
||||||
|
39
pyrogram/client/methods/__init__.py
Normal file
39
pyrogram/client/methods/__init__.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# 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 .bots import Bots
|
||||||
|
from .chats import Chats
|
||||||
|
from .contacts import Contacts
|
||||||
|
from .decorators import Decorators
|
||||||
|
from .download_media import DownloadMedia
|
||||||
|
from .messages import Messages
|
||||||
|
from .password import Password
|
||||||
|
from .users import Users
|
||||||
|
|
||||||
|
|
||||||
|
class Methods(
|
||||||
|
Bots,
|
||||||
|
Contacts,
|
||||||
|
Password,
|
||||||
|
Chats,
|
||||||
|
Users,
|
||||||
|
DownloadMedia,
|
||||||
|
Messages,
|
||||||
|
Decorators
|
||||||
|
):
|
||||||
|
pass
|
27
pyrogram/client/methods/bots/__init__.py
Normal file
27
pyrogram/client/methods/bots/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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 .callback_query import CallbackQuery
|
||||||
|
from .inline import Inline
|
||||||
|
|
||||||
|
|
||||||
|
class Bots(
|
||||||
|
CallbackQuery,
|
||||||
|
Inline
|
||||||
|
):
|
||||||
|
pass
|
25
pyrogram/client/methods/bots/callback_query/__init__.py
Normal file
25
pyrogram/client/methods/bots/callback_query/__init__.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .answer_callback_query import AnswerCallbackQuery
|
||||||
|
|
||||||
|
|
||||||
|
class CallbackQuery(
|
||||||
|
AnswerCallbackQuery
|
||||||
|
):
|
||||||
|
pass
|
@ -0,0 +1,62 @@
|
|||||||
|
# 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 AnswerCallbackQuery(BaseClient):
|
||||||
|
def answer_callback_query(self,
|
||||||
|
callback_query_id: str,
|
||||||
|
text: str = None,
|
||||||
|
show_alert: bool = None,
|
||||||
|
url: str = None,
|
||||||
|
cache_time: int = 0):
|
||||||
|
"""Use this method to send answers to callback queries sent from inline keyboards.
|
||||||
|
The answer will be displayed to the user as a notification at the top of the chat screen or as an alert.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
callback_query_id (``str``):
|
||||||
|
Unique identifier for the query to be answered.
|
||||||
|
|
||||||
|
text (``str``):
|
||||||
|
Text of the notification. If not specified, nothing will be shown to the user, 0-200 characters.
|
||||||
|
|
||||||
|
show_alert (``bool``):
|
||||||
|
If true, an alert will be shown by the client instead of a notification at the top of the chat screen.
|
||||||
|
Defaults to False.
|
||||||
|
|
||||||
|
url (``str``):
|
||||||
|
URL that will be opened by the user's client.
|
||||||
|
If you have created a Game and accepted the conditions via @Botfather, specify the URL that opens your
|
||||||
|
game – note that this will only work if the query comes from a callback_game button.
|
||||||
|
Otherwise, you may use links like t.me/your_bot?start=XXXX that open your bot with a parameter.
|
||||||
|
|
||||||
|
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.
|
||||||
|
"""
|
||||||
|
return self.send(
|
||||||
|
functions.messages.SetBotCallbackAnswer(
|
||||||
|
query_id=int(callback_query_id),
|
||||||
|
cache_time=cache_time,
|
||||||
|
alert=show_alert or None,
|
||||||
|
message=text,
|
||||||
|
url=url
|
||||||
|
)
|
||||||
|
)
|
27
pyrogram/client/methods/bots/inline/__init__.py
Normal file
27
pyrogram/client/methods/bots/inline/__init__.py
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
# 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 .get_inline_bot_results import GetInlineBotResults
|
||||||
|
from .send_inline_bot_result import SendInlineBotResult
|
||||||
|
|
||||||
|
|
||||||
|
class Inline(
|
||||||
|
SendInlineBotResult,
|
||||||
|
GetInlineBotResults
|
||||||
|
):
|
||||||
|
pass
|
@ -0,0 +1,80 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import UnknownError
|
||||||
|
from ....ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class GetInlineBotResults(BaseClient):
|
||||||
|
def get_inline_bot_results(self,
|
||||||
|
bot: int or str,
|
||||||
|
query: str,
|
||||||
|
offset: str = "",
|
||||||
|
latitude: float = None,
|
||||||
|
longitude: float = None):
|
||||||
|
"""Use this method to get bot results via inline queries.
|
||||||
|
You can then send a result using :obj:`send_inline_bot_result <pyrogram.Client.send_inline_bot_result>`
|
||||||
|
|
||||||
|
Args:
|
||||||
|
bot (``int`` | ``str``):
|
||||||
|
Unique identifier of the inline bot you want to get results from. You can specify
|
||||||
|
a @username (str) or a bot ID (int).
|
||||||
|
|
||||||
|
query (``str``):
|
||||||
|
Text of the query (up to 512 characters).
|
||||||
|
|
||||||
|
offset (``str``, *optional*):
|
||||||
|
Offset of the results to be returned.
|
||||||
|
|
||||||
|
latitude (``float``, *optional*):
|
||||||
|
Latitude of the location.
|
||||||
|
Useful for location-based results only.
|
||||||
|
|
||||||
|
longitude (``float``, *optional*):
|
||||||
|
Longitude of the location.
|
||||||
|
Useful for location-based results only.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
# TODO: Don't return the raw type
|
||||||
|
|
||||||
|
try:
|
||||||
|
return self.send(
|
||||||
|
functions.messages.GetInlineBotResults(
|
||||||
|
bot=self.resolve_peer(bot),
|
||||||
|
peer=types.InputPeerSelf(),
|
||||||
|
query=query,
|
||||||
|
offset=offset,
|
||||||
|
geo_point=types.InputGeoPoint(
|
||||||
|
lat=latitude,
|
||||||
|
long=longitude
|
||||||
|
) if (latitude is not None and longitude is not None) else None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except UnknownError as e:
|
||||||
|
# TODO: Add this -503 Timeout error into the Error DB
|
||||||
|
if e.x.error_code == -503 and e.x.error_message == "Timeout":
|
||||||
|
raise TimeoutError("The inline bot didn't answer in time") from None
|
||||||
|
else:
|
||||||
|
raise e
|
@ -0,0 +1,68 @@
|
|||||||
|
# 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 SendInlineBotResult(BaseClient):
|
||||||
|
def send_inline_bot_result(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
query_id: int,
|
||||||
|
result_id: str,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None):
|
||||||
|
"""Use this method to send an inline bot result.
|
||||||
|
Bot results can be retrieved using :obj:`get_inline_bot_results <pyrogram.Client.get_inline_bot_results>`
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
query_id (``int``):
|
||||||
|
Unique identifier for the answered query.
|
||||||
|
|
||||||
|
result_id (``str``):
|
||||||
|
Unique identifier for the result that was chosen.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``bool``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent Message is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
return self.send(
|
||||||
|
functions.messages.SendInlineBotResult(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
query_id=query_id,
|
||||||
|
id=result_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id
|
||||||
|
)
|
||||||
|
)
|
31
pyrogram/client/methods/chats/__init__.py
Normal file
31
pyrogram/client/methods/chats/__init__.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# 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 .export_chat_invite_link import ExportChatInviteLink
|
||||||
|
from .get_chat import GetChat
|
||||||
|
from .join_chat import JoinChat
|
||||||
|
from .leave_chat import LeaveChat
|
||||||
|
|
||||||
|
|
||||||
|
class Chats(
|
||||||
|
GetChat,
|
||||||
|
ExportChatInviteLink,
|
||||||
|
LeaveChat,
|
||||||
|
JoinChat
|
||||||
|
):
|
||||||
|
pass
|
53
pyrogram/client/methods/chats/export_chat_invite_link.py
Normal file
53
pyrogram/client/methods/chats/export_chat_invite_link.py
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class ExportChatInviteLink(BaseClient):
|
||||||
|
def export_chat_invite_link(self, chat_id: int or str):
|
||||||
|
"""Use this method to generate a new invite link for a chat; any previously generated link is revoked.
|
||||||
|
|
||||||
|
You must be an administrator in the chat for this to work and have the appropriate admin rights.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier for the target chat or username of the target channel/supergroup
|
||||||
|
(in the format @username).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the exported invite link as string is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
peer = self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
if isinstance(peer, types.InputPeerChat):
|
||||||
|
return self.send(
|
||||||
|
functions.messages.ExportChatInvite(
|
||||||
|
chat_id=peer.chat_id
|
||||||
|
)
|
||||||
|
).link
|
||||||
|
elif isinstance(peer, types.InputPeerChannel):
|
||||||
|
return self.send(
|
||||||
|
functions.channels.ExportInvite(
|
||||||
|
channel=peer
|
||||||
|
)
|
||||||
|
).link
|
35
pyrogram/client/methods/chats/get_chat.py
Normal file
35
pyrogram/client/methods/chats/get_chat.py
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetChat(BaseClient):
|
||||||
|
def get_chat(self, chat_id: int or str):
|
||||||
|
# TODO: Add docstrings
|
||||||
|
peer = self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
if isinstance(peer, types.InputPeerChannel):
|
||||||
|
r = self.send(functions.channels.GetFullChannel(peer))
|
||||||
|
elif isinstance(peer, (types.InputPeerUser, types.InputPeerSelf)):
|
||||||
|
r = self.send(functions.users.GetFullUser(peer))
|
||||||
|
else:
|
||||||
|
r = self.send(functions.messages.GetFullChat(peer.chat_id))
|
||||||
|
|
||||||
|
return utils.parse_chat_full(self, r)
|
59
pyrogram/client/methods/chats/join_chat.py
Normal file
59
pyrogram/client/methods/chats/join_chat.py
Normal file
@ -0,0 +1,59 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class JoinChat(BaseClient):
|
||||||
|
def join_chat(self, chat_id: str):
|
||||||
|
"""Use this method to join a group chat or channel.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``str``):
|
||||||
|
Unique identifier for the target chat in form of *t.me/joinchat/* links or username of the target
|
||||||
|
channel/supergroup (in the format @username).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
match = self.INVITE_LINK_RE.match(chat_id)
|
||||||
|
|
||||||
|
if match:
|
||||||
|
return self.send(
|
||||||
|
functions.messages.ImportChatInvite(
|
||||||
|
hash=match.group(1)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
resolved_peer = self.send(
|
||||||
|
functions.contacts.ResolveUsername(
|
||||||
|
username=chat_id.lower().strip("@")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
channel = types.InputPeerChannel(
|
||||||
|
channel_id=resolved_peer.chats[0].id,
|
||||||
|
access_hash=resolved_peer.chats[0].access_hash
|
||||||
|
)
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.channels.JoinChannel(
|
||||||
|
channel=channel
|
||||||
|
)
|
||||||
|
)
|
62
pyrogram/client/methods/chats/leave_chat.py
Normal file
62
pyrogram/client/methods/chats/leave_chat.py
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class LeaveChat(BaseClient):
|
||||||
|
def leave_chat(self, chat_id: int or str, delete: bool = False):
|
||||||
|
"""Use this method to leave a group chat or channel.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier for the target chat or username of the target channel/supergroup
|
||||||
|
(in the format @username).
|
||||||
|
|
||||||
|
delete (``bool``, *optional*):
|
||||||
|
Deletes the group chat dialog after leaving (for simple group chats, not supergroups).
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
peer = self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
if isinstance(peer, types.InputPeerChannel):
|
||||||
|
return self.send(
|
||||||
|
functions.channels.LeaveChannel(
|
||||||
|
channel=self.resolve_peer(chat_id)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(peer, types.InputPeerChat):
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.DeleteChatUser(
|
||||||
|
chat_id=peer.chat_id,
|
||||||
|
user_id=types.InputPeerSelf()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if delete:
|
||||||
|
self.send(
|
||||||
|
functions.messages.DeleteHistory(
|
||||||
|
peer=peer,
|
||||||
|
max_id=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return r
|
29
pyrogram/client/methods/contacts/__init__.py
Normal file
29
pyrogram/client/methods/contacts/__init__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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 .add_contacts import AddContacts
|
||||||
|
from .delete_contacts import DeleteContacts
|
||||||
|
from .get_contacts import GetContacts
|
||||||
|
|
||||||
|
|
||||||
|
class Contacts(
|
||||||
|
GetContacts,
|
||||||
|
DeleteContacts,
|
||||||
|
AddContacts
|
||||||
|
):
|
||||||
|
pass
|
43
pyrogram/client/methods/contacts/add_contacts.py
Normal file
43
pyrogram/client/methods/contacts/add_contacts.py
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
# 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 AddContacts(BaseClient):
|
||||||
|
def add_contacts(self, contacts: list):
|
||||||
|
"""Use this method to add contacts to your Telegram address book.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
contacts (``list``):
|
||||||
|
A list of :obj:`InputPhoneContact <pyrogram.InputPhoneContact>`
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the added contacts are returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
imported_contacts = self.send(
|
||||||
|
functions.contacts.ImportContacts(
|
||||||
|
contacts=contacts
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return imported_contacts
|
54
pyrogram/client/methods/contacts/delete_contacts.py
Normal file
54
pyrogram/client/methods/contacts/delete_contacts.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 pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import PeerIdInvalid
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteContacts(BaseClient):
|
||||||
|
def delete_contacts(self, ids: list):
|
||||||
|
"""Use this method to delete contacts from your Telegram address book
|
||||||
|
|
||||||
|
Args:
|
||||||
|
ids (``list``):
|
||||||
|
A list of unique identifiers for the target users.
|
||||||
|
Can be an ID (int), a username (string) or phone number (string).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True on success.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
contacts = []
|
||||||
|
|
||||||
|
for i in ids:
|
||||||
|
try:
|
||||||
|
input_user = self.resolve_peer(i)
|
||||||
|
except PeerIdInvalid:
|
||||||
|
continue
|
||||||
|
else:
|
||||||
|
if isinstance(input_user, types.InputPeerUser):
|
||||||
|
contacts.append(input_user)
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.contacts.DeleteContacts(
|
||||||
|
id=contacts
|
||||||
|
)
|
||||||
|
)
|
42
pyrogram/client/methods/contacts/get_contacts.py
Normal file
42
pyrogram/client/methods/contacts/get_contacts.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 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 logging
|
||||||
|
import time
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FloodWait
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GetContacts(BaseClient):
|
||||||
|
def get_contacts(self, _hash: int = 0):
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
contacts = self.send(functions.contacts.GetContacts(_hash))
|
||||||
|
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
|
25
pyrogram/client/methods/decorators/__init__.py
Normal file
25
pyrogram/client/methods/decorators/__init__.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .on_callback_query import OnCallbackQuery
|
||||||
|
from .on_message import OnMessage
|
||||||
|
from .on_raw_update import OnRawUpdate
|
||||||
|
|
||||||
|
|
||||||
|
class Decorators(OnMessage, OnCallbackQuery, OnRawUpdate):
|
||||||
|
pass
|
42
pyrogram/client/methods/decorators/on_callback_query.py
Normal file
42
pyrogram/client/methods/decorators/on_callback_query.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 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 ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class OnCallbackQuery(BaseClient):
|
||||||
|
def on_callback_query(self, filters=None, group: int = 0):
|
||||||
|
"""Use this decorator to automatically register a function for handling
|
||||||
|
callback queries. This does the same thing as :meth:`add_handler` using the
|
||||||
|
CallbackQueryHandler.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||||
|
Pass one or more filters to allow only a subset of callback queries to be passed
|
||||||
|
in your function.
|
||||||
|
|
||||||
|
group (``int``, *optional*):
|
||||||
|
The group identifier, defaults to 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
self.add_handler(pyrogram.CallbackQueryHandler(func, filters), group)
|
||||||
|
return func
|
||||||
|
|
||||||
|
return decorator
|
42
pyrogram/client/methods/decorators/on_message.py
Normal file
42
pyrogram/client/methods/decorators/on_message.py
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
# 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 ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class OnMessage(BaseClient):
|
||||||
|
def on_message(self, 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
|
||||||
|
MessageHandler.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
filters (:obj:`Filters <pyrogram.Filters>`):
|
||||||
|
Pass one or more filters to allow only a subset of messages to be passed
|
||||||
|
in your function.
|
||||||
|
|
||||||
|
group (``int``, *optional*):
|
||||||
|
The group identifier, defaults to 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
self.add_handler(pyrogram.MessageHandler(func, filters), group)
|
||||||
|
return func
|
||||||
|
|
||||||
|
return decorator
|
38
pyrogram/client/methods/decorators/on_raw_update.py
Normal file
38
pyrogram/client/methods/decorators/on_raw_update.py
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
# 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 ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class OnRawUpdate(BaseClient):
|
||||||
|
def on_raw_update(self, 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
|
||||||
|
RawUpdateHandler.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
group (``int``, *optional*):
|
||||||
|
The group identifier, defaults to 0.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def decorator(func):
|
||||||
|
self.add_handler(pyrogram.RawUpdateHandler(func), group)
|
||||||
|
return func
|
||||||
|
|
||||||
|
return decorator
|
122
pyrogram/client/methods/download_media.py
Normal file
122
pyrogram/client/methods/download_media.py
Normal file
@ -0,0 +1,122 @@
|
|||||||
|
# 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 threading import Event
|
||||||
|
|
||||||
|
from pyrogram.client import types as pyrogram_types
|
||||||
|
from ..ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class DownloadMedia(BaseClient):
|
||||||
|
def download_media(self,
|
||||||
|
message: pyrogram_types.Message or str,
|
||||||
|
file_name: str = "",
|
||||||
|
block: bool = True,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = None):
|
||||||
|
"""Use this method to download the media from a Message.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
message (:obj:`Message <pyrogram.Message>` | ``str``):
|
||||||
|
Pass a Message containing the media, the media itself (message.audio, message.video, ...) or
|
||||||
|
the file id as string.
|
||||||
|
|
||||||
|
file_name (``str``, *optional*):
|
||||||
|
A custom *file_name* to be used instead of the one provided by Telegram.
|
||||||
|
By default, all files are downloaded in the *downloads* folder in your working directory.
|
||||||
|
You can also specify a path for downloading files in a custom location: paths that end with "/"
|
||||||
|
are considered directories. All non-existent folders will be created automatically.
|
||||||
|
|
||||||
|
block (``bool``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes downloaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the absolute path of the downloaded file as string is returned, None otherwise.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
if isinstance(message, pyrogram_types.Message):
|
||||||
|
if message.photo:
|
||||||
|
media = message.photo[-1]
|
||||||
|
elif message.audio:
|
||||||
|
media = message.audio
|
||||||
|
elif message.document:
|
||||||
|
media = message.document
|
||||||
|
elif message.video:
|
||||||
|
media = message.video
|
||||||
|
elif message.voice:
|
||||||
|
media = message.voice
|
||||||
|
elif message.video_note:
|
||||||
|
media = message.video_note
|
||||||
|
elif message.sticker:
|
||||||
|
media = message.sticker
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
elif isinstance(message, (
|
||||||
|
pyrogram_types.PhotoSize,
|
||||||
|
pyrogram_types.Audio,
|
||||||
|
pyrogram_types.Document,
|
||||||
|
pyrogram_types.Video,
|
||||||
|
pyrogram_types.Voice,
|
||||||
|
pyrogram_types.VideoNote,
|
||||||
|
pyrogram_types.Sticker
|
||||||
|
)):
|
||||||
|
media = message
|
||||||
|
elif isinstance(message, str):
|
||||||
|
media = pyrogram_types.Document(
|
||||||
|
file_id=message,
|
||||||
|
file_size=0,
|
||||||
|
mime_type=""
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return
|
||||||
|
|
||||||
|
done = Event()
|
||||||
|
path = [None]
|
||||||
|
|
||||||
|
self.download_queue.put((media, file_name, done, progress, progress_args, path))
|
||||||
|
|
||||||
|
if block:
|
||||||
|
done.wait()
|
||||||
|
|
||||||
|
return path[0]
|
37
pyrogram/client/methods/messages/__init__.py
Normal file
37
pyrogram/client/methods/messages/__init__.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
# 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 .action import Action
|
||||||
|
from .forward_messages import ForwardMessages
|
||||||
|
from .get_history import GetHistory
|
||||||
|
from .get_messages import GetMessages
|
||||||
|
from .media import Media
|
||||||
|
from .send_message import SendMessage
|
||||||
|
from .update import Update
|
||||||
|
|
||||||
|
|
||||||
|
class Messages(
|
||||||
|
GetHistory,
|
||||||
|
GetMessages,
|
||||||
|
Action,
|
||||||
|
Media,
|
||||||
|
Update,
|
||||||
|
ForwardMessages,
|
||||||
|
SendMessage
|
||||||
|
):
|
||||||
|
pass
|
25
pyrogram/client/methods/messages/action/__init__.py
Normal file
25
pyrogram/client/methods/messages/action/__init__.py
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from .send_chat_action import SendChatAction
|
||||||
|
|
||||||
|
|
||||||
|
class Action(
|
||||||
|
SendChatAction
|
||||||
|
):
|
||||||
|
pass
|
71
pyrogram/client/methods/messages/action/send_chat_action.py
Normal file
71
pyrogram/client/methods/messages/action/send_chat_action.py
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
# 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, ChatAction
|
||||||
|
|
||||||
|
|
||||||
|
class SendChatAction(BaseClient):
|
||||||
|
def send_chat_action(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
action: ChatAction or str,
|
||||||
|
progress: int = 0):
|
||||||
|
"""Use this method when you need to tell the other party that something is happening on your side.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
action (:obj:`ChatAction <pyrogram.ChatAction>` | ``str``):
|
||||||
|
Type of action to broadcast.
|
||||||
|
Choose one from the :class:`ChatAction <pyrogram.ChatAction>` enumeration,
|
||||||
|
depending on what the user is about to receive.
|
||||||
|
You can also provide a string (e.g. "typing", "upload_photo", "record_audio", ...).
|
||||||
|
|
||||||
|
progress (``int``, *optional*):
|
||||||
|
Progress of the upload process.
|
||||||
|
Currently useless because official clients don't seem to be handling this.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, True is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
``ValueError``: If the provided string is not a valid ChatAction
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Resolve Enum type
|
||||||
|
if isinstance(action, str):
|
||||||
|
action = ChatAction.from_string(action).value
|
||||||
|
elif isinstance(action, ChatAction):
|
||||||
|
action = action.value
|
||||||
|
|
||||||
|
if "Upload" in action.__name__:
|
||||||
|
action = action(progress)
|
||||||
|
else:
|
||||||
|
action = action()
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.messages.SetTyping(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
action=action
|
||||||
|
)
|
||||||
|
)
|
88
pyrogram/client/methods/messages/forward_messages.py
Normal file
88
pyrogram/client/methods/messages/forward_messages.py
Normal file
@ -0,0 +1,88 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class ForwardMessages(BaseClient):
|
||||||
|
def forward_messages(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
from_chat_id: int or str,
|
||||||
|
message_ids,
|
||||||
|
disable_notification: bool = None):
|
||||||
|
"""Use this method to forward messages of any kind.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
from_chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the source chat where the original message was sent.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
message_ids (``iterable``):
|
||||||
|
A list of Message identifiers in the chat specified in *from_chat_id* or a single message id.
|
||||||
|
Iterators and Generators are also accepted.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success and in case *message_ids* was a list, the returned value will be a list of the forwarded
|
||||||
|
:obj:`Messages <pyrogram.Message>` even if a list contains just one element, otherwise if
|
||||||
|
*message_ids* was an integer, the single forwarded :obj:`Message <pyrogram.Message>`
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
is_iterable = not isinstance(message_ids, int)
|
||||||
|
message_ids = list(message_ids) if is_iterable else [message_ids]
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.ForwardMessages(
|
||||||
|
to_peer=self.resolve_peer(chat_id),
|
||||||
|
from_peer=self.resolve_peer(from_chat_id),
|
||||||
|
id=message_ids,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
random_id=[self.rnd_id() for _ in message_ids]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
messages = []
|
||||||
|
|
||||||
|
users = {i.id: i for i in r.users}
|
||||||
|
chats = {i.id: i for i in r.chats}
|
||||||
|
|
||||||
|
for i in r.updates:
|
||||||
|
if isinstance(i, (types.UpdateNewMessage, types.UpdateNewChannelMessage)):
|
||||||
|
messages.append(
|
||||||
|
utils.parse_messages(
|
||||||
|
self, i.message,
|
||||||
|
users, chats
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return messages if is_iterable else messages[0]
|
101
pyrogram/client/methods/messages/get_history.py
Normal file
101
pyrogram/client/methods/messages/get_history.py
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
# 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, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetHistory(BaseClient):
|
||||||
|
def get_history(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
offset: int = 0,
|
||||||
|
limit: int = 100,
|
||||||
|
offset_id: int = 0,
|
||||||
|
offset_date: int = 0):
|
||||||
|
"""Use this method to retrieve the history of a chat.
|
||||||
|
|
||||||
|
You can get up to 100 messages at once.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
offset (``int``, *optional*)
|
||||||
|
Sequential number of the first message to be returned.
|
||||||
|
Defaults to 0 (most recent message).
|
||||||
|
|
||||||
|
limit (``int``, *optional*):
|
||||||
|
Limits the number of messages to be retrieved.
|
||||||
|
By default, the first 100 messages are returned.
|
||||||
|
|
||||||
|
offset_id (``int``, *optional*):
|
||||||
|
Pass a message identifier as offset to retrieve only older messages starting from that message.
|
||||||
|
|
||||||
|
offset_date (``int``, *optional*):
|
||||||
|
Pass a date in Unix time as offset to retrieve only older messages starting from that date.
|
||||||
|
"""
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.GetHistory(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
offset_id=offset_id,
|
||||||
|
offset_date=offset_date,
|
||||||
|
add_offset=offset,
|
||||||
|
limit=limit,
|
||||||
|
max_id=0,
|
||||||
|
min_id=0,
|
||||||
|
hash=0
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
users = {i.id: i for i in r.users}
|
||||||
|
chats = {i.id: i for i in r.chats}
|
||||||
|
|
||||||
|
reply_to_messages = {
|
||||||
|
i.reply_to_msg_id: None
|
||||||
|
for i in r.messages
|
||||||
|
if i.reply_to_msg_id
|
||||||
|
}
|
||||||
|
|
||||||
|
if reply_to_messages:
|
||||||
|
temp = self.get_messages(
|
||||||
|
chat_id, reply_to_messages,
|
||||||
|
replies=0
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(temp) == len(reply_to_messages)
|
||||||
|
|
||||||
|
for i in range(len(temp)):
|
||||||
|
reply_to_messages[temp[i].message_id] = temp[i]
|
||||||
|
|
||||||
|
messages = utils.parse_messages(
|
||||||
|
self, r.messages,
|
||||||
|
users, chats,
|
||||||
|
replies=0
|
||||||
|
)
|
||||||
|
|
||||||
|
assert len(messages) == len(r.messages)
|
||||||
|
|
||||||
|
for i in range(len(messages)):
|
||||||
|
if r.messages[i].reply_to_msg_id:
|
||||||
|
messages[i].reply_to_message = reply_to_messages[r.messages[i].reply_to_msg_id]
|
||||||
|
|
||||||
|
return messages
|
78
pyrogram/client/methods/messages/get_messages.py
Normal file
78
pyrogram/client/methods/messages/get_messages.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetMessages(BaseClient):
|
||||||
|
def get_messages(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_ids,
|
||||||
|
replies: int = 1):
|
||||||
|
"""Use this method to get messages that belong to a specific chat.
|
||||||
|
You can retrieve up to 200 messages at once.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
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.Message>` even if a list contains just one element, otherwise if
|
||||||
|
*message_ids* was an integer, the single requested :obj:`Message <pyrogram.Message>`
|
||||||
|
is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
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]
|
||||||
|
|
||||||
|
if isinstance(peer, types.InputPeerChannel):
|
||||||
|
rpc = functions.channels.GetMessages(
|
||||||
|
channel=peer,
|
||||||
|
id=message_ids
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
rpc = functions.messages.GetMessages(
|
||||||
|
id=message_ids
|
||||||
|
)
|
||||||
|
|
||||||
|
r = self.send(rpc)
|
||||||
|
|
||||||
|
messages = utils.parse_messages(
|
||||||
|
self, r.messages,
|
||||||
|
{i.id: i for i in r.users},
|
||||||
|
{i.id: i for i in r.chats},
|
||||||
|
replies=replies
|
||||||
|
)
|
||||||
|
|
||||||
|
return messages if is_iterable else messages[0]
|
45
pyrogram/client/methods/messages/media/__init__.py
Normal file
45
pyrogram/client/methods/messages/media/__init__.py
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
# 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 .send_audio import SendAudio
|
||||||
|
from .send_contact import SendContact
|
||||||
|
from .send_document import SendDocument
|
||||||
|
from .send_media_group import SendMediaGroup
|
||||||
|
from .send_photo import SendPhoto
|
||||||
|
from .send_sticker import SendSticker
|
||||||
|
from .send_location import SendLocation
|
||||||
|
from .send_venue import SendVenue
|
||||||
|
from .send_video import SendVideo
|
||||||
|
from .send_video_note import SendVideoNote
|
||||||
|
from .send_voice import SendVoice
|
||||||
|
|
||||||
|
|
||||||
|
class Media(
|
||||||
|
SendContact,
|
||||||
|
SendVenue,
|
||||||
|
SendLocation,
|
||||||
|
SendMediaGroup,
|
||||||
|
SendVideoNote,
|
||||||
|
SendVoice,
|
||||||
|
SendVideo,
|
||||||
|
SendSticker,
|
||||||
|
SendDocument,
|
||||||
|
SendAudio,
|
||||||
|
SendPhoto
|
||||||
|
):
|
||||||
|
pass
|
183
pyrogram/client/methods/messages/media/send_audio.py
Normal file
183
pyrogram/client/methods/messages/media/send_audio.py
Normal file
@ -0,0 +1,183 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendAudio(BaseClient):
|
||||||
|
def send_audio(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
audio: str,
|
||||||
|
caption: str = "",
|
||||||
|
parse_mode: str = "",
|
||||||
|
duration: int = 0,
|
||||||
|
performer: str = None,
|
||||||
|
title: str = None,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send audio files.
|
||||||
|
|
||||||
|
For sending voice messages, use the :obj:`send_voice()` method instead.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
audio (``str``):
|
||||||
|
Audio file to send.
|
||||||
|
Pass a file_id as string to send an audio file that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get an audio file from the Internet, or
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
duration (``int``, *optional*):
|
||||||
|
Duration of the audio in seconds.
|
||||||
|
|
||||||
|
performer (``str``, *optional*):
|
||||||
|
Performer.
|
||||||
|
|
||||||
|
title (``str``, *optional*):
|
||||||
|
Track name.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
if os.path.exists(audio):
|
||||||
|
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"),
|
||||||
|
file=file,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeAudio(
|
||||||
|
duration=duration,
|
||||||
|
performer=performer,
|
||||||
|
title=title
|
||||||
|
),
|
||||||
|
types.DocumentAttributeFilename(os.path.basename(audio))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif audio.startswith("http"):
|
||||||
|
media = types.InputMediaDocumentExternal(
|
||||||
|
url=audio
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(audio)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 9:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(audio, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
89
pyrogram/client/methods/messages/media/send_contact.py
Normal file
89
pyrogram/client/methods/messages/media/send_contact.py
Normal file
@ -0,0 +1,89 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendContact(BaseClient):
|
||||||
|
def send_contact(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
phone_number: str,
|
||||||
|
first_name: str,
|
||||||
|
last_name: str = "",
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to send phone contacts.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
phone_number (``str``):
|
||||||
|
Contact's phone number.
|
||||||
|
|
||||||
|
first_name (``str``):
|
||||||
|
Contact's first name.
|
||||||
|
|
||||||
|
last_name (``str``, *optional*):
|
||||||
|
Contact's last name.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=types.InputMediaContact(
|
||||||
|
phone_number,
|
||||||
|
first_name,
|
||||||
|
last_name
|
||||||
|
),
|
||||||
|
message="",
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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}
|
||||||
|
)
|
164
pyrogram/client/methods/messages/media/send_document.py
Normal file
164
pyrogram/client/methods/messages/media/send_document.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendDocument(BaseClient):
|
||||||
|
def send_document(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
document: str,
|
||||||
|
caption: str = "",
|
||||||
|
parse_mode: str = "",
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send general files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
document (``str``):
|
||||||
|
File to send.
|
||||||
|
Pass a file_id as string to send a file that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get a file from the Internet, or
|
||||||
|
pass a file path as string to upload a new file that exists on your local machine.
|
||||||
|
|
||||||
|
caption (``str``, *optional*):
|
||||||
|
Document caption, 0-200 characters.
|
||||||
|
|
||||||
|
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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
if os.path.exists(document):
|
||||||
|
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"),
|
||||||
|
file=file,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeFilename(os.path.basename(document))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif document.startswith("http"):
|
||||||
|
media = types.InputMediaDocumentExternal(
|
||||||
|
url=document
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(document)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] not in (5, 10):
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(document, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
86
pyrogram/client/methods/messages/media/send_location.py
Normal file
86
pyrogram/client/methods/messages/media/send_location.py
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendLocation(BaseClient):
|
||||||
|
def send_location(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
latitude: float,
|
||||||
|
longitude: float,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to send points on the map.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
latitude (``float``):
|
||||||
|
Latitude of the location.
|
||||||
|
|
||||||
|
longitude (``float``):
|
||||||
|
Longitude of the location.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=types.InputMediaGeoPoint(
|
||||||
|
types.InputGeoPoint(
|
||||||
|
latitude,
|
||||||
|
longitude
|
||||||
|
)
|
||||||
|
),
|
||||||
|
message="",
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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}
|
||||||
|
)
|
170
pyrogram/client/methods/messages/media/send_media_group.py
Normal file
170
pyrogram/client/methods/messages/media/send_media_group.py
Normal file
@ -0,0 +1,170 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid
|
||||||
|
from pyrogram.client import types as pyrogram_types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
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: int or str,
|
||||||
|
media: list,
|
||||||
|
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``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
media (``list``):
|
||||||
|
A list containing either :obj:`InputMediaPhoto <pyrogram.InputMediaPhoto>` or
|
||||||
|
:obj:`InputMediaVideo <pyrogram.InputMediaVideo>` objects
|
||||||
|
describing photos and videos to be sent, must include 2–10 items.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
"""
|
||||||
|
multi_media = []
|
||||||
|
|
||||||
|
for i in media:
|
||||||
|
style = self.html if i.parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
if isinstance(i, pyrogram_types.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)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
media = types.InputMediaPhoto(
|
||||||
|
id=types.InputPhoto(
|
||||||
|
id=media.photo.id,
|
||||||
|
access_hash=media.photo.access_hash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(i.media)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 2:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaPhoto(
|
||||||
|
id=types.InputPhoto(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif isinstance(i, pyrogram_types.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),
|
||||||
|
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))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=media.document.id,
|
||||||
|
access_hash=media.document.access_hash
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(i.media)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 4:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
multi_media.append(
|
||||||
|
types.InputSingleMedia(
|
||||||
|
media=media,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
**style.parse(i.caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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
|
||||||
|
)
|
||||||
|
)
|
168
pyrogram/client/methods/messages/media/send_photo.py
Normal file
168
pyrogram/client/methods/messages/media/send_photo.py
Normal file
@ -0,0 +1,168 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendPhoto(BaseClient):
|
||||||
|
def send_photo(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
photo: str,
|
||||||
|
caption: str = "",
|
||||||
|
parse_mode: str = "",
|
||||||
|
ttl_seconds: int = None,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send photos.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
photo (``str``):
|
||||||
|
Photo to send.
|
||||||
|
Pass a file_id as string to send a photo that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get a photo from the Internet, or
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
ttl_seconds (``int``, *optional*):
|
||||||
|
Self-Destruct Timer.
|
||||||
|
If you set a timer, the photo will self-destruct in *ttl_seconds*
|
||||||
|
seconds after it was viewed.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
if os.path.exists(photo):
|
||||||
|
file = self.save_file(photo, progress=progress, progress_args=progress_args)
|
||||||
|
media = types.InputMediaUploadedPhoto(
|
||||||
|
file=file,
|
||||||
|
ttl_seconds=ttl_seconds
|
||||||
|
)
|
||||||
|
elif photo.startswith("http"):
|
||||||
|
media = types.InputMediaPhotoExternal(
|
||||||
|
url=photo,
|
||||||
|
ttl_seconds=ttl_seconds
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(photo)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 2:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaPhoto(
|
||||||
|
id=types.InputPhoto(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
),
|
||||||
|
ttl_seconds=ttl_seconds
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(photo, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
152
pyrogram/client/methods/messages/media/send_sticker.py
Normal file
152
pyrogram/client/methods/messages/media/send_sticker.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendSticker(BaseClient):
|
||||||
|
def send_sticker(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
sticker: str,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send .webp stickers.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
sticker (``str``):
|
||||||
|
Sticker to send.
|
||||||
|
Pass a file_id as string to send a sticker that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get a .webp sticker file from the Internet, or
|
||||||
|
pass a file path as string to upload a new sticker that exists on your local machine.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
|
||||||
|
if os.path.exists(sticker):
|
||||||
|
file = self.save_file(sticker, progress=progress, progress_args=progress_args)
|
||||||
|
media = types.InputMediaUploadedDocument(
|
||||||
|
mime_type="image/webp",
|
||||||
|
file=file,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeFilename(os.path.basename(sticker))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif sticker.startswith("http"):
|
||||||
|
media = types.InputMediaDocumentExternal(
|
||||||
|
url=sticker
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(sticker)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 8:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
message=""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(sticker, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
103
pyrogram/client/methods/messages/media/send_venue.py
Normal file
103
pyrogram/client/methods/messages/media/send_venue.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendVenue(BaseClient):
|
||||||
|
def send_venue(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
latitude: float,
|
||||||
|
longitude: float,
|
||||||
|
title: str,
|
||||||
|
address: str,
|
||||||
|
foursquare_id: str = "",
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to send information about a venue.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
latitude (``float``):
|
||||||
|
Latitude of the venue.
|
||||||
|
|
||||||
|
longitude (``float``):
|
||||||
|
Longitude of the venue.
|
||||||
|
|
||||||
|
title (``str``):
|
||||||
|
Name of the venue.
|
||||||
|
|
||||||
|
address (``str``):
|
||||||
|
Address of the venue.
|
||||||
|
|
||||||
|
foursquare_id (``str``, *optional*):
|
||||||
|
Foursquare identifier of the venue.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=types.InputMediaVenue(
|
||||||
|
geo_point=types.InputGeoPoint(
|
||||||
|
lat=latitude,
|
||||||
|
long=longitude
|
||||||
|
),
|
||||||
|
title=title,
|
||||||
|
address=address,
|
||||||
|
provider="",
|
||||||
|
venue_id=foursquare_id,
|
||||||
|
venue_type=""
|
||||||
|
),
|
||||||
|
message="",
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
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}
|
||||||
|
)
|
194
pyrogram/client/methods/messages/media/send_video.py
Normal file
194
pyrogram/client/methods/messages/media/send_video.py
Normal file
@ -0,0 +1,194 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendVideo(BaseClient):
|
||||||
|
def send_video(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
video: str,
|
||||||
|
caption: str = "",
|
||||||
|
parse_mode: str = "",
|
||||||
|
duration: int = 0,
|
||||||
|
width: int = 0,
|
||||||
|
height: int = 0,
|
||||||
|
thumb: str = None,
|
||||||
|
supports_streaming: bool = True,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send video files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
video (``str``):
|
||||||
|
Video to send.
|
||||||
|
Pass a file_id as string to send a video that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get a video from the Internet, or
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
duration (``int``, *optional*):
|
||||||
|
Duration of sent video in seconds.
|
||||||
|
|
||||||
|
width (``int``, *optional*):
|
||||||
|
Video width.
|
||||||
|
|
||||||
|
height (``int``, *optional*):
|
||||||
|
Video height.
|
||||||
|
|
||||||
|
thumb (``str``, *optional*):
|
||||||
|
Video thumbnail.
|
||||||
|
Pass a file path as string to send an image that exists on your local machine.
|
||||||
|
Thumbnail should have 90 or less pixels of width and 90 or less pixels of height.
|
||||||
|
|
||||||
|
supports_streaming (``bool``, *optional*):
|
||||||
|
Pass True, if the uploaded video is suitable for streaming.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
if os.path.exists(video):
|
||||||
|
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"],
|
||||||
|
file=file,
|
||||||
|
thumb=thumb,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeVideo(
|
||||||
|
supports_streaming=supports_streaming or None,
|
||||||
|
duration=duration,
|
||||||
|
w=width,
|
||||||
|
h=height
|
||||||
|
),
|
||||||
|
types.DocumentAttributeFilename(os.path.basename(video))
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif video.startswith("http"):
|
||||||
|
media = types.InputMediaDocumentExternal(
|
||||||
|
url=video
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(video)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 4:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(video, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
162
pyrogram/client/methods/messages/media/send_video_note.py
Normal file
162
pyrogram/client/methods/messages/media/send_video_note.py
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendVideoNote(BaseClient):
|
||||||
|
def send_video_note(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
video_note: str,
|
||||||
|
duration: int = 0,
|
||||||
|
length: int = 1,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send video messages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
video_note (``str``):
|
||||||
|
Video note to send.
|
||||||
|
Pass a file_id as string to send a video note that exists on the Telegram servers, or
|
||||||
|
pass a file path as string to upload a new video note that exists on your local machine.
|
||||||
|
Sending video notes by a URL is currently unsupported.
|
||||||
|
|
||||||
|
duration (``int``, *optional*):
|
||||||
|
Duration of sent video in seconds.
|
||||||
|
|
||||||
|
length (``int``, *optional*):
|
||||||
|
Video width and height.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
|
||||||
|
if os.path.exists(video_note):
|
||||||
|
file = self.save_file(video_note, progress=progress, progress_args=progress_args)
|
||||||
|
media = types.InputMediaUploadedDocument(
|
||||||
|
mime_type=mimetypes.types_map[".mp4"],
|
||||||
|
file=file,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeVideo(
|
||||||
|
round_message=True,
|
||||||
|
duration=duration,
|
||||||
|
w=length,
|
||||||
|
h=length
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(video_note)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 13:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
message=""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(video_note, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
171
pyrogram/client/methods/messages/media/send_voice.py
Normal file
171
pyrogram/client/methods/messages/media/send_voice.py
Normal file
@ -0,0 +1,171 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import binascii
|
||||||
|
import mimetypes
|
||||||
|
import os
|
||||||
|
import struct
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.api.errors import FileIdInvalid, FilePartMissing
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class SendVoice(BaseClient):
|
||||||
|
def send_voice(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
voice: str,
|
||||||
|
caption: str = "",
|
||||||
|
parse_mode: str = "",
|
||||||
|
duration: int = 0,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None,
|
||||||
|
progress: callable = None,
|
||||||
|
progress_args: tuple = ()):
|
||||||
|
"""Use this method to send audio files.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
voice (``str``):
|
||||||
|
Audio file to send.
|
||||||
|
Pass a file_id as string to send an audio that exists on the Telegram servers,
|
||||||
|
pass an HTTP URL as a string for Telegram to get an audio from the Internet, or
|
||||||
|
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.
|
||||||
|
|
||||||
|
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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
duration (``int``, *optional*):
|
||||||
|
Duration of the voice message in seconds.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
progress (``callable``, *optional*):
|
||||||
|
Pass a callback function to view the upload progress.
|
||||||
|
The function must take *(client, current, total, \*args)* as positional arguments (look at the section
|
||||||
|
below for a detailed description).
|
||||||
|
|
||||||
|
progress_args (``tuple``, *optional*):
|
||||||
|
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.
|
||||||
|
|
||||||
|
Other Parameters:
|
||||||
|
client (:obj:`Client <pyrogram.Client>`):
|
||||||
|
The Client itself, useful when you want to call other API methods inside the callback function.
|
||||||
|
|
||||||
|
current (``int``):
|
||||||
|
The amount of bytes uploaded so far.
|
||||||
|
|
||||||
|
total (``int``):
|
||||||
|
The size of the file.
|
||||||
|
|
||||||
|
*args (``tuple``):
|
||||||
|
Extra custom arguments as defined in the *progress_args* parameter.
|
||||||
|
You can either keep *\*args* or add every single extra argument in your function signature.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
file = None
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
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"),
|
||||||
|
file=file,
|
||||||
|
attributes=[
|
||||||
|
types.DocumentAttributeAudio(
|
||||||
|
voice=True,
|
||||||
|
duration=duration
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
elif voice.startswith("http"):
|
||||||
|
media = types.InputMediaDocumentExternal(
|
||||||
|
url=voice
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
try:
|
||||||
|
decoded = utils.decode(voice)
|
||||||
|
fmt = "<iiqqqqi" if len(decoded) > 24 else "<iiqq"
|
||||||
|
unpacked = struct.unpack(fmt, decoded)
|
||||||
|
except (AssertionError, binascii.Error, struct.error):
|
||||||
|
raise FileIdInvalid from None
|
||||||
|
else:
|
||||||
|
if unpacked[0] != 3:
|
||||||
|
media_type = BaseClient.MEDIA_TYPE_ID.get(unpacked[0], None)
|
||||||
|
|
||||||
|
if media_type:
|
||||||
|
raise FileIdInvalid("The file_id belongs to a {}".format(media_type))
|
||||||
|
else:
|
||||||
|
raise FileIdInvalid("Unknown media type: {}".format(unpacked[0]))
|
||||||
|
|
||||||
|
media = types.InputMediaDocument(
|
||||||
|
id=types.InputDocument(
|
||||||
|
id=unpacked[2],
|
||||||
|
access_hash=unpacked[3]
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
while True:
|
||||||
|
try:
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMedia(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
media=media,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
except FilePartMissing as e:
|
||||||
|
self.save_file(voice, file_id=file.id, file_part=e.x)
|
||||||
|
else:
|
||||||
|
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}
|
||||||
|
)
|
98
pyrogram/client/methods/messages/send_message.py
Normal file
98
pyrogram/client/methods/messages/send_message.py
Normal file
@ -0,0 +1,98 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from pyrogram.client import types as pyrogram_types
|
||||||
|
from ...ext import utils, BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class SendMessage(BaseClient):
|
||||||
|
def send_message(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
text: str,
|
||||||
|
parse_mode: str = "",
|
||||||
|
disable_web_page_preview: bool = None,
|
||||||
|
disable_notification: bool = None,
|
||||||
|
reply_to_message_id: int = None,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to send text messages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
text (``str``):
|
||||||
|
Text of the message to be sent.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
disable_notification (``bool``, *optional*):
|
||||||
|
Sends the message silently.
|
||||||
|
Users will receive a notification with no sound.
|
||||||
|
|
||||||
|
reply_to_message_id (``int``, *optional*):
|
||||||
|
If the message is a reply, ID of the original message.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup` | :obj:`ReplyKeyboardMarkup` | :obj:`ReplyKeyboardRemove` | :obj:`ForceReply`, *optional*):
|
||||||
|
Additional interface options. An object for an inline keyboard, custom reply keyboard,
|
||||||
|
instructions to remove reply keyboard or to force a reply from the user.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the sent Message is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.SendMessage(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
no_webpage=disable_web_page_preview or None,
|
||||||
|
silent=disable_notification or None,
|
||||||
|
reply_to_msg_id=reply_to_message_id,
|
||||||
|
random_id=self.rnd_id(),
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(text)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if isinstance(r, types.UpdateShortSentMessage):
|
||||||
|
return pyrogram_types.Message(
|
||||||
|
message_id=r.id,
|
||||||
|
date=r.date,
|
||||||
|
outgoing=r.out,
|
||||||
|
entities=utils.parse_entities(r.entities, {}) or None
|
||||||
|
)
|
||||||
|
|
||||||
|
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}
|
||||||
|
)
|
31
pyrogram/client/methods/messages/update/__init__.py
Normal file
31
pyrogram/client/methods/messages/update/__init__.py
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
# 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 .delete_messages import DeleteMessages
|
||||||
|
from .edit_message_caption import EditMessageCaption
|
||||||
|
from .edit_message_reply_markup import EditMessageReplyMarkup
|
||||||
|
from .edit_message_text import EditMessageText
|
||||||
|
|
||||||
|
|
||||||
|
class Update(
|
||||||
|
DeleteMessages,
|
||||||
|
EditMessageReplyMarkup,
|
||||||
|
EditMessageCaption,
|
||||||
|
EditMessageText
|
||||||
|
):
|
||||||
|
pass
|
77
pyrogram/client/methods/messages/update/delete_messages.py
Normal file
77
pyrogram/client/methods/messages/update/delete_messages.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteMessages(BaseClient):
|
||||||
|
def delete_messages(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_ids,
|
||||||
|
revoke: bool = True):
|
||||||
|
"""Use this method to delete messages, including service messages, with the following limitations:
|
||||||
|
|
||||||
|
- A message can only be deleted if it was sent less than 48 hours ago.
|
||||||
|
- Users can delete outgoing messages in groups and supergroups.
|
||||||
|
- Users granted *can_post_messages* permissions can delete outgoing messages in channels.
|
||||||
|
- If the user is an administrator of a group, it can delete any message there.
|
||||||
|
- If the user has *can_delete_messages* permission in a supergroup or a channel, it can delete any message there.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
message_ids (``iterable``):
|
||||||
|
A list of Message identifiers to delete or a single message id.
|
||||||
|
Iterators and Generators are also accepted.
|
||||||
|
|
||||||
|
revoke (``bool``, *optional*):
|
||||||
|
Deletes messages on both parts.
|
||||||
|
This is only for private cloud chats and normal groups, messages on
|
||||||
|
channels and supergroups are always revoked (i.e.: deleted for everyone).
|
||||||
|
Defaults to True.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True on success.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
peer = self.resolve_peer(chat_id)
|
||||||
|
message_ids = list(message_ids) if not isinstance(message_ids, int) else [message_ids]
|
||||||
|
|
||||||
|
if isinstance(peer, types.InputPeerChannel):
|
||||||
|
self.send(
|
||||||
|
functions.channels.DeleteMessages(
|
||||||
|
channel=peer,
|
||||||
|
id=message_ids
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
self.send(
|
||||||
|
functions.messages.DeleteMessages(
|
||||||
|
id=message_ids,
|
||||||
|
revoke=revoke or None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return True
|
@ -0,0 +1,76 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class EditMessageCaption(BaseClient):
|
||||||
|
def edit_message_caption(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_id: int,
|
||||||
|
caption: str,
|
||||||
|
parse_mode: str = "",
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to edit captions of messages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
message_id (``int``):
|
||||||
|
Message identifier in the chat specified in chat_id.
|
||||||
|
|
||||||
|
caption (``str``):
|
||||||
|
New caption 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 caption.
|
||||||
|
Defaults to Markdown.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
|
||||||
|
An InlineKeyboardMarkup object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, the edited :obj:`Message <pyrogram.Message>` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.EditMessage(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
id=message_id,
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(caption)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in r.updates:
|
||||||
|
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
|
||||||
|
return utils.parse_messages(
|
||||||
|
self, i.message,
|
||||||
|
{i.id: i for i in r.users},
|
||||||
|
{i.id: i for i in r.chats}
|
||||||
|
)
|
@ -0,0 +1,65 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class EditMessageReplyMarkup(BaseClient):
|
||||||
|
def edit_message_reply_markup(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_id: int,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to edit only the reply markup of messages sent by the bot or via the bot (for inline bots).
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
message_id (``int``):
|
||||||
|
Message identifier in the chat specified in chat_id.
|
||||||
|
|
||||||
|
reply_markup (:obj:`InlineKeyboardMarkup`, *optional*):
|
||||||
|
An InlineKeyboardMarkup object.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, if edited message is sent by the bot, the edited
|
||||||
|
:obj:`Message <pyrogram.Message>` is returned, otherwise True is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.EditMessage(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
id=message_id,
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in r.updates:
|
||||||
|
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
|
||||||
|
return utils.parse_messages(
|
||||||
|
self, i.message,
|
||||||
|
{i.id: i for i in r.users},
|
||||||
|
{i.id: i for i in r.chats}
|
||||||
|
)
|
81
pyrogram/client/methods/messages/update/edit_message_text.py
Normal file
81
pyrogram/client/methods/messages/update/edit_message_text.py
Normal file
@ -0,0 +1,81 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ....ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class EditMessageText(BaseClient):
|
||||||
|
def edit_message_text(self,
|
||||||
|
chat_id: int or str,
|
||||||
|
message_id: int,
|
||||||
|
text: str,
|
||||||
|
parse_mode: str = "",
|
||||||
|
disable_web_page_preview: bool = None,
|
||||||
|
reply_markup=None):
|
||||||
|
"""Use this method to edit text messages.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
message_id (``int``):
|
||||||
|
Message identifier in the chat specified in chat_id.
|
||||||
|
|
||||||
|
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>`
|
||||||
|
"""
|
||||||
|
style = self.html if parse_mode.lower() == "html" else self.markdown
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.messages.EditMessage(
|
||||||
|
peer=self.resolve_peer(chat_id),
|
||||||
|
id=message_id,
|
||||||
|
no_webpage=disable_web_page_preview or None,
|
||||||
|
reply_markup=reply_markup.write() if reply_markup else None,
|
||||||
|
**style.parse(text)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
for i in r.updates:
|
||||||
|
if isinstance(i, (types.UpdateEditMessage, types.UpdateEditChannelMessage)):
|
||||||
|
return utils.parse_messages(
|
||||||
|
self, i.message,
|
||||||
|
{i.id: i for i in r.users},
|
||||||
|
{i.id: i for i in r.chats}
|
||||||
|
)
|
29
pyrogram/client/methods/password/__init__.py
Normal file
29
pyrogram/client/methods/password/__init__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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 .change_cloud_password import ChangeCloudPassword
|
||||||
|
from .enable_cloud_password import EnableCloudPassword
|
||||||
|
from .remove_cloud_password import RemoveCloudPassword
|
||||||
|
|
||||||
|
|
||||||
|
class Password(
|
||||||
|
RemoveCloudPassword,
|
||||||
|
ChangeCloudPassword,
|
||||||
|
EnableCloudPassword
|
||||||
|
):
|
||||||
|
pass
|
65
pyrogram/client/methods/password/change_cloud_password.py
Normal file
65
pyrogram/client/methods/password/change_cloud_password.py
Normal file
@ -0,0 +1,65 @@
|
|||||||
|
# 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 os
|
||||||
|
from hashlib import sha256
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class ChangeCloudPassword(BaseClient):
|
||||||
|
def change_cloud_password(self, current_password: str, new_password: str, new_hint: str = ""):
|
||||||
|
"""Use this method to change your Two-Step Verification password (Cloud Password) with a new one.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
current_password (``str``):
|
||||||
|
Your current password.
|
||||||
|
|
||||||
|
new_password (``str``):
|
||||||
|
Your new password.
|
||||||
|
|
||||||
|
new_hint (``str``, *optional*):
|
||||||
|
A new password hint.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True on success, False otherwise.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(functions.account.GetPassword())
|
||||||
|
|
||||||
|
if isinstance(r, types.account.Password):
|
||||||
|
current_password_hash = sha256(r.current_salt + current_password.encode() + r.current_salt).digest()
|
||||||
|
|
||||||
|
new_salt = r.new_salt + os.urandom(8)
|
||||||
|
new_password_hash = sha256(new_salt + new_password.encode() + new_salt).digest()
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.account.UpdatePasswordSettings(
|
||||||
|
current_password_hash=current_password_hash,
|
||||||
|
new_settings=types.account.PasswordInputSettings(
|
||||||
|
new_salt=new_salt,
|
||||||
|
new_password_hash=new_password_hash,
|
||||||
|
hint=new_hint
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
66
pyrogram/client/methods/password/enable_cloud_password.py
Normal file
66
pyrogram/client/methods/password/enable_cloud_password.py
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# 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 os
|
||||||
|
from hashlib import sha256
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class EnableCloudPassword(BaseClient):
|
||||||
|
def enable_cloud_password(self, password: str, hint: str = "", email: str = ""):
|
||||||
|
"""Use this method to enable the Two-Step Verification security feature (Cloud Password) on your account.
|
||||||
|
|
||||||
|
This password will be asked when you log in on a new device in addition to the SMS code.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (``str``):
|
||||||
|
Your password.
|
||||||
|
|
||||||
|
hint (``str``, *optional*):
|
||||||
|
A password hint.
|
||||||
|
|
||||||
|
email (``str``, *optional*):
|
||||||
|
Recovery e-mail.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True on success, False otherwise.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(functions.account.GetPassword())
|
||||||
|
|
||||||
|
if isinstance(r, types.account.NoPassword):
|
||||||
|
salt = r.new_salt + os.urandom(8)
|
||||||
|
password_hash = sha256(salt + password.encode() + salt).digest()
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.account.UpdatePasswordSettings(
|
||||||
|
current_password_hash=salt,
|
||||||
|
new_settings=types.account.PasswordInputSettings(
|
||||||
|
new_salt=salt,
|
||||||
|
new_password_hash=password_hash,
|
||||||
|
hint=hint,
|
||||||
|
email=email
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
55
pyrogram/client/methods/password/remove_cloud_password.py
Normal file
55
pyrogram/client/methods/password/remove_cloud_password.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# 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 hashlib import sha256
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient
|
||||||
|
|
||||||
|
|
||||||
|
class RemoveCloudPassword(BaseClient):
|
||||||
|
def remove_cloud_password(self, password: str):
|
||||||
|
"""Use this method to turn off the Two-Step Verification security feature (Cloud Password) on your account.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
password (``str``):
|
||||||
|
Your current password.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
True on success, False otherwise.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
r = self.send(functions.account.GetPassword())
|
||||||
|
|
||||||
|
if isinstance(r, types.account.Password):
|
||||||
|
password_hash = sha256(r.current_salt + password.encode() + r.current_salt).digest()
|
||||||
|
|
||||||
|
return self.send(
|
||||||
|
functions.account.UpdatePasswordSettings(
|
||||||
|
current_password_hash=password_hash,
|
||||||
|
new_settings=types.account.PasswordInputSettings(
|
||||||
|
new_salt=b"",
|
||||||
|
new_password_hash=b"",
|
||||||
|
hint=""
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return False
|
29
pyrogram/client/methods/users/__init__.py
Normal file
29
pyrogram/client/methods/users/__init__.py
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
# 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 .get_me import GetMe
|
||||||
|
from .get_user_profile_photos import GetUserProfilePhotos
|
||||||
|
from .get_users import GetUsers
|
||||||
|
|
||||||
|
|
||||||
|
class Users(
|
||||||
|
GetUserProfilePhotos,
|
||||||
|
GetUsers,
|
||||||
|
GetMe
|
||||||
|
):
|
||||||
|
pass
|
39
pyrogram/client/methods/users/get_me.py
Normal file
39
pyrogram/client/methods/users/get_me.py
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2017-2018 Dan Tès <https://github.com/delivrance>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrogram.
|
||||||
|
#
|
||||||
|
# Pyrogram is free software: you can redistribute it and/or modify
|
||||||
|
# it under the terms of the GNU Lesser General Public License as published
|
||||||
|
# by the Free Software Foundation, either version 3 of the License, or
|
||||||
|
# (at your option) any later version.
|
||||||
|
#
|
||||||
|
# Pyrogram is distributed in the hope that it will be useful,
|
||||||
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
# GNU Lesser General Public License for more details.
|
||||||
|
#
|
||||||
|
# You should have received a copy of the GNU Lesser General Public License
|
||||||
|
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram.api import functions, types
|
||||||
|
from ...ext import BaseClient, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetMe(BaseClient):
|
||||||
|
def get_me(self):
|
||||||
|
"""A simple method for testing your authorization. Requires no parameters.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Basic information about the user or bot in form of a :obj:`User` object
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
return utils.parse_user(
|
||||||
|
self.send(
|
||||||
|
functions.users.GetFullUser(
|
||||||
|
types.InputPeerSelf()
|
||||||
|
)
|
||||||
|
).user
|
||||||
|
)
|
60
pyrogram/client/methods/users/get_user_profile_photos.py
Normal file
60
pyrogram/client/methods/users/get_user_profile_photos.py
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
# 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, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetUserProfilePhotos(BaseClient):
|
||||||
|
def get_user_profile_photos(self,
|
||||||
|
user_id: int or str,
|
||||||
|
offset: int = 0,
|
||||||
|
limit: int = 100):
|
||||||
|
"""Use this method to get a list of profile pictures for a user.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
For your personal cloud (Saved Messages) you can simply use "me" or "self".
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
For a private channel/supergroup you can use its *t.me/joinchat/* link.
|
||||||
|
|
||||||
|
offset (``int``, *optional*):
|
||||||
|
Sequential number of the first photo to be returned.
|
||||||
|
By default, all photos are returned.
|
||||||
|
|
||||||
|
limit (``int``, *optional*):
|
||||||
|
Limits the number of photos to be retrieved.
|
||||||
|
Values between 1—100 are accepted. Defaults to 100.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success, a :obj:`UserProfilePhotos` object is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
return utils.parse_photos(
|
||||||
|
self.send(
|
||||||
|
functions.photos.GetUserPhotos(
|
||||||
|
user_id=self.resolve_peer(user_id),
|
||||||
|
offset=offset,
|
||||||
|
max_id=0,
|
||||||
|
limit=limit
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
57
pyrogram/client/methods/users/get_users.py
Normal file
57
pyrogram/client/methods/users/get_users.py
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
# 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, utils
|
||||||
|
|
||||||
|
|
||||||
|
class GetUsers(BaseClient):
|
||||||
|
def get_users(self, user_ids):
|
||||||
|
"""Use this method to get information about a user.
|
||||||
|
You can retrieve up to 200 users at once.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
user_ids (``iterable``):
|
||||||
|
A list of User identifiers (id or username) or a single user id/username.
|
||||||
|
For a contact that exists in your Telegram address book you can use his phone number (str).
|
||||||
|
Iterators and Generators are also accepted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
On success and in case *user_ids* was a list, the returned value will be a list of the requested
|
||||||
|
:obj:`Users <User>` even if a list contains just one element, otherwise if
|
||||||
|
*user_ids* was an integer, the single requested :obj:`User` is returned.
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
:class:`Error <pyrogram.Error>`
|
||||||
|
"""
|
||||||
|
is_iterable = not isinstance(user_ids, (int, str))
|
||||||
|
user_ids = list(user_ids) if is_iterable else [user_ids]
|
||||||
|
user_ids = [self.resolve_peer(i) for i in user_ids]
|
||||||
|
|
||||||
|
r = self.send(
|
||||||
|
functions.users.GetUsers(
|
||||||
|
id=user_ids
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
users = []
|
||||||
|
|
||||||
|
for i in r:
|
||||||
|
users.append(utils.parse_user(i))
|
||||||
|
|
||||||
|
return users if is_iterable else users[0]
|
@ -16,7 +16,6 @@
|
|||||||
# 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 pyrogram.api.core import Object
|
from pyrogram.api.core import Object
|
||||||
from pyrogram.api.types import ReplyKeyboardHide
|
from pyrogram.api.types import ReplyKeyboardHide
|
||||||
|
|
||||||
|
@ -1,787 +0,0 @@
|
|||||||
# 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 base64 import b64decode, b64encode
|
|
||||||
from struct import pack
|
|
||||||
from weakref import proxy
|
|
||||||
|
|
||||||
from pyrogram.client import types as pyrogram_types
|
|
||||||
from ..api import types, functions
|
|
||||||
from ..api.errors import StickersetInvalid
|
|
||||||
|
|
||||||
# TODO: Organize the code better?
|
|
||||||
|
|
||||||
ENTITIES = {
|
|
||||||
types.MessageEntityMention.ID: "mention",
|
|
||||||
types.MessageEntityHashtag.ID: "hashtag",
|
|
||||||
types.MessageEntityBotCommand.ID: "bot_command",
|
|
||||||
types.MessageEntityUrl.ID: "url",
|
|
||||||
types.MessageEntityEmail.ID: "email",
|
|
||||||
types.MessageEntityBold.ID: "bold",
|
|
||||||
types.MessageEntityItalic.ID: "italic",
|
|
||||||
types.MessageEntityCode.ID: "code",
|
|
||||||
types.MessageEntityPre.ID: "pre",
|
|
||||||
types.MessageEntityTextUrl.ID: "text_link",
|
|
||||||
types.MessageEntityMentionName.ID: "text_mention"
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
def parse_entities(entities: list, users: dict) -> list:
|
|
||||||
output_entities = []
|
|
||||||
|
|
||||||
for entity in entities:
|
|
||||||
entity_type = ENTITIES.get(entity.ID, None)
|
|
||||||
|
|
||||||
if entity_type:
|
|
||||||
output_entities.append(pyrogram_types.MessageEntity(
|
|
||||||
type=entity_type,
|
|
||||||
offset=entity.offset,
|
|
||||||
length=entity.length,
|
|
||||||
url=getattr(entity, "url", None),
|
|
||||||
user=parse_user(
|
|
||||||
users.get(
|
|
||||||
getattr(entity, "user_id", None),
|
|
||||||
None
|
|
||||||
)
|
|
||||||
)
|
|
||||||
))
|
|
||||||
|
|
||||||
return output_entities
|
|
||||||
|
|
||||||
|
|
||||||
def parse_chat_photo(photo):
|
|
||||||
if not isinstance(photo, (types.UserProfilePhoto, types.ChatPhoto)):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not isinstance(photo.photo_small, types.FileLocation):
|
|
||||||
return None
|
|
||||||
|
|
||||||
if not isinstance(photo.photo_big, types.FileLocation):
|
|
||||||
return None
|
|
||||||
|
|
||||||
photo_id = getattr(photo, "photo_id", 0)
|
|
||||||
loc_small = photo.photo_small
|
|
||||||
loc_big = photo.photo_big
|
|
||||||
|
|
||||||
return pyrogram_types.ChatPhoto(
|
|
||||||
small_file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi", 1, loc_small.dc_id, photo_id, 0, loc_small.volume_id,
|
|
||||||
loc_small.secret, loc_small.local_id
|
|
||||||
)
|
|
||||||
),
|
|
||||||
big_file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi", 1, loc_big.dc_id, photo_id, 0, loc_big.volume_id,
|
|
||||||
loc_big.secret, loc_big.local_id
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_user(user: types.User) -> pyrogram_types.User or None:
|
|
||||||
return pyrogram_types.User(
|
|
||||||
id=user.id,
|
|
||||||
is_bot=user.bot,
|
|
||||||
first_name=user.first_name,
|
|
||||||
last_name=user.last_name,
|
|
||||||
username=user.username,
|
|
||||||
language_code=user.lang_code,
|
|
||||||
phone_number=user.phone,
|
|
||||||
photo=parse_chat_photo(user.photo)
|
|
||||||
) if user else None
|
|
||||||
|
|
||||||
|
|
||||||
def parse_chat(message: types.Message, users: dict, chats: dict) -> pyrogram_types.Chat:
|
|
||||||
if isinstance(message.to_id, types.PeerUser):
|
|
||||||
return parse_user_chat(users[message.to_id.user_id if message.out else message.from_id])
|
|
||||||
elif isinstance(message.to_id, types.PeerChat):
|
|
||||||
return parse_chat_chat(chats[message.to_id.chat_id])
|
|
||||||
else:
|
|
||||||
return parse_channel_chat(chats[message.to_id.channel_id])
|
|
||||||
|
|
||||||
|
|
||||||
def parse_user_chat(user: types.User) -> pyrogram_types.Chat:
|
|
||||||
return pyrogram_types.Chat(
|
|
||||||
id=user.id,
|
|
||||||
type="private",
|
|
||||||
username=user.username,
|
|
||||||
first_name=user.first_name,
|
|
||||||
last_name=user.last_name,
|
|
||||||
photo=parse_chat_photo(user.photo)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_chat_chat(chat: types.Chat) -> pyrogram_types.Chat:
|
|
||||||
admins_enabled = getattr(chat, "admins_enabled", None)
|
|
||||||
|
|
||||||
if admins_enabled is not None:
|
|
||||||
admins_enabled = not admins_enabled
|
|
||||||
|
|
||||||
return pyrogram_types.Chat(
|
|
||||||
id=-chat.id,
|
|
||||||
type="group",
|
|
||||||
title=chat.title,
|
|
||||||
all_members_are_administrators=admins_enabled,
|
|
||||||
photo=parse_chat_photo(getattr(chat, "photo", None))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_channel_chat(channel: types.Channel) -> pyrogram_types.Chat:
|
|
||||||
return pyrogram_types.Chat(
|
|
||||||
id=int("-100" + str(channel.id)),
|
|
||||||
type="supergroup" if channel.megagroup else "channel",
|
|
||||||
title=channel.title,
|
|
||||||
username=getattr(channel, "username", None),
|
|
||||||
photo=parse_chat_photo(getattr(channel, "photo", None))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_thumb(thumb: types.PhotoSize or types.PhotoCachedSize) -> pyrogram_types.PhotoSize or None:
|
|
||||||
if isinstance(thumb, (types.PhotoSize, types.PhotoCachedSize)):
|
|
||||||
loc = thumb.location
|
|
||||||
|
|
||||||
if isinstance(thumb, types.PhotoSize):
|
|
||||||
file_size = thumb.size
|
|
||||||
else:
|
|
||||||
file_size = len(thumb.bytes)
|
|
||||||
|
|
||||||
if isinstance(loc, types.FileLocation):
|
|
||||||
return pyrogram_types.PhotoSize(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi",
|
|
||||||
0,
|
|
||||||
loc.dc_id,
|
|
||||||
0,
|
|
||||||
0,
|
|
||||||
loc.volume_id,
|
|
||||||
loc.secret,
|
|
||||||
loc.local_id
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=thumb.w,
|
|
||||||
height=thumb.h,
|
|
||||||
file_size=file_size
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def decode(s: str) -> bytes:
|
|
||||||
s = b64decode(s + "=" * (-len(s) % 4), "-_")
|
|
||||||
r = b""
|
|
||||||
|
|
||||||
assert s[-1] == 2
|
|
||||||
|
|
||||||
i = 0
|
|
||||||
while i < len(s) - 1:
|
|
||||||
if s[i] != 0:
|
|
||||||
r += bytes([s[i]])
|
|
||||||
else:
|
|
||||||
r += b"\x00" * s[i + 1]
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
i += 1
|
|
||||||
|
|
||||||
return r
|
|
||||||
|
|
||||||
|
|
||||||
def encode(s: bytes) -> str:
|
|
||||||
r = b""
|
|
||||||
n = 0
|
|
||||||
|
|
||||||
for i in s + bytes([2]):
|
|
||||||
if i == 0:
|
|
||||||
n += 1
|
|
||||||
else:
|
|
||||||
if n:
|
|
||||||
r += b"\x00" + bytes([n])
|
|
||||||
n = 0
|
|
||||||
|
|
||||||
r += bytes([i])
|
|
||||||
|
|
||||||
return b64encode(r, b"-_").decode().rstrip("=")
|
|
||||||
|
|
||||||
|
|
||||||
# TODO: Reorganize code, maybe split parts as well
|
|
||||||
def parse_message(
|
|
||||||
client,
|
|
||||||
message: types.Message,
|
|
||||||
users: dict,
|
|
||||||
chats: dict,
|
|
||||||
replies: int = 1
|
|
||||||
) -> pyrogram_types.Message:
|
|
||||||
entities = parse_entities(message.entities, users)
|
|
||||||
|
|
||||||
forward_from = None
|
|
||||||
forward_from_chat = None
|
|
||||||
forward_from_message_id = None
|
|
||||||
forward_signature = None
|
|
||||||
forward_date = None
|
|
||||||
|
|
||||||
forward_header = message.fwd_from # type: types.MessageFwdHeader
|
|
||||||
|
|
||||||
if forward_header:
|
|
||||||
forward_date = forward_header.date
|
|
||||||
|
|
||||||
if forward_header.from_id:
|
|
||||||
forward_from = parse_user(users[forward_header.from_id])
|
|
||||||
else:
|
|
||||||
forward_from_chat = parse_channel_chat(chats[forward_header.channel_id])
|
|
||||||
forward_from_message_id = forward_header.channel_post
|
|
||||||
forward_signature = forward_header.post_author
|
|
||||||
|
|
||||||
photo = None
|
|
||||||
location = None
|
|
||||||
contact = None
|
|
||||||
venue = None
|
|
||||||
audio = None
|
|
||||||
voice = None
|
|
||||||
video = None
|
|
||||||
video_note = None
|
|
||||||
sticker = None
|
|
||||||
document = None
|
|
||||||
|
|
||||||
media = message.media
|
|
||||||
|
|
||||||
if media:
|
|
||||||
if isinstance(media, types.MessageMediaPhoto):
|
|
||||||
photo = media.photo
|
|
||||||
|
|
||||||
if isinstance(photo, types.Photo):
|
|
||||||
sizes = photo.sizes
|
|
||||||
photo_sizes = []
|
|
||||||
|
|
||||||
for size in sizes:
|
|
||||||
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
|
||||||
loc = size.location
|
|
||||||
|
|
||||||
if isinstance(size, types.PhotoSize):
|
|
||||||
file_size = size.size
|
|
||||||
else:
|
|
||||||
file_size = len(size.bytes)
|
|
||||||
|
|
||||||
if isinstance(loc, types.FileLocation):
|
|
||||||
photo_size = pyrogram_types.PhotoSize(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi",
|
|
||||||
2,
|
|
||||||
loc.dc_id,
|
|
||||||
photo.id,
|
|
||||||
photo.access_hash,
|
|
||||||
loc.volume_id,
|
|
||||||
loc.secret,
|
|
||||||
loc.local_id
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=size.w,
|
|
||||||
height=size.h,
|
|
||||||
file_size=file_size,
|
|
||||||
date=photo.date
|
|
||||||
)
|
|
||||||
|
|
||||||
photo_sizes.append(photo_size)
|
|
||||||
|
|
||||||
photo = photo_sizes
|
|
||||||
elif isinstance(media, types.MessageMediaGeo):
|
|
||||||
geo_point = media.geo
|
|
||||||
|
|
||||||
if isinstance(geo_point, types.GeoPoint):
|
|
||||||
location = pyrogram_types.Location(
|
|
||||||
longitude=geo_point.long,
|
|
||||||
latitude=geo_point.lat
|
|
||||||
)
|
|
||||||
elif isinstance(media, types.MessageMediaContact):
|
|
||||||
contact = pyrogram_types.Contact(
|
|
||||||
phone_number=media.phone_number,
|
|
||||||
first_name=media.first_name,
|
|
||||||
last_name=media.last_name or None,
|
|
||||||
user_id=media.user_id or None
|
|
||||||
)
|
|
||||||
elif isinstance(media, types.MessageMediaVenue):
|
|
||||||
venue = pyrogram_types.Venue(
|
|
||||||
location=pyrogram_types.Location(
|
|
||||||
longitude=media.geo.long,
|
|
||||||
latitude=media.geo.lat
|
|
||||||
),
|
|
||||||
title=media.title,
|
|
||||||
address=media.address,
|
|
||||||
foursquare_id=media.venue_id or None
|
|
||||||
)
|
|
||||||
elif isinstance(media, types.MessageMediaDocument):
|
|
||||||
doc = media.document
|
|
||||||
|
|
||||||
if isinstance(doc, types.Document):
|
|
||||||
attributes = {type(i): i for i in doc.attributes}
|
|
||||||
|
|
||||||
file_name = getattr(
|
|
||||||
attributes.get(
|
|
||||||
types.DocumentAttributeFilename, None
|
|
||||||
), "file_name", None
|
|
||||||
)
|
|
||||||
|
|
||||||
if types.DocumentAttributeAudio in attributes:
|
|
||||||
audio_attributes = attributes[types.DocumentAttributeAudio]
|
|
||||||
|
|
||||||
if audio_attributes.voice:
|
|
||||||
voice = pyrogram_types.Voice(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
3,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
duration=audio_attributes.duration,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_size=doc.size,
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
file_name=file_name,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
audio = pyrogram_types.Audio(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
9,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
duration=audio_attributes.duration,
|
|
||||||
performer=audio_attributes.performer,
|
|
||||||
title=audio_attributes.title,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_size=doc.size,
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
file_name=file_name,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
elif types.DocumentAttributeAnimated in attributes:
|
|
||||||
document = pyrogram_types.Document(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
10,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
file_name=file_name,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_size=doc.size,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
elif types.DocumentAttributeVideo in attributes:
|
|
||||||
video_attributes = attributes[types.DocumentAttributeVideo]
|
|
||||||
|
|
||||||
if video_attributes.round_message:
|
|
||||||
video_note = pyrogram_types.VideoNote(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
13,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
length=video_attributes.w,
|
|
||||||
duration=video_attributes.duration,
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
file_size=doc.size,
|
|
||||||
file_name=file_name,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
video = pyrogram_types.Video(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
4,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=video_attributes.w,
|
|
||||||
height=video_attributes.h,
|
|
||||||
duration=video_attributes.duration,
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_size=doc.size,
|
|
||||||
file_name=file_name,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
elif types.DocumentAttributeSticker in attributes:
|
|
||||||
image_size_attributes = attributes.get(types.DocumentAttributeImageSize, None)
|
|
||||||
sticker_attribute = attributes[types.DocumentAttributeSticker]
|
|
||||||
|
|
||||||
if isinstance(sticker_attribute.stickerset, types.InputStickerSetID):
|
|
||||||
try:
|
|
||||||
set_name = client.send(
|
|
||||||
functions.messages.GetStickerSet(sticker_attribute.stickerset)
|
|
||||||
).set.short_name
|
|
||||||
except StickersetInvalid:
|
|
||||||
set_name = None
|
|
||||||
else:
|
|
||||||
set_name = None
|
|
||||||
|
|
||||||
sticker = pyrogram_types.Sticker(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
8,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=image_size_attributes.w if image_size_attributes else 0,
|
|
||||||
height=image_size_attributes.h if image_size_attributes else 0,
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
# TODO: mask_position
|
|
||||||
set_name=set_name,
|
|
||||||
emoji=sticker_attribute.alt or None,
|
|
||||||
file_size=doc.size,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_name=file_name,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
document = pyrogram_types.Document(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqq",
|
|
||||||
5,
|
|
||||||
doc.dc_id,
|
|
||||||
doc.id,
|
|
||||||
doc.access_hash
|
|
||||||
)
|
|
||||||
),
|
|
||||||
thumb=parse_thumb(doc.thumb),
|
|
||||||
file_name=file_name,
|
|
||||||
mime_type=doc.mime_type,
|
|
||||||
file_size=doc.size,
|
|
||||||
date=doc.date
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
media = None
|
|
||||||
|
|
||||||
reply_markup = message.reply_markup
|
|
||||||
|
|
||||||
if reply_markup:
|
|
||||||
if isinstance(reply_markup, types.ReplyKeyboardForceReply):
|
|
||||||
reply_markup = pyrogram_types.ForceReply.read(reply_markup)
|
|
||||||
elif isinstance(reply_markup, types.ReplyKeyboardMarkup):
|
|
||||||
reply_markup = pyrogram_types.ReplyKeyboardMarkup.read(reply_markup)
|
|
||||||
elif isinstance(reply_markup, types.ReplyInlineMarkup):
|
|
||||||
reply_markup = pyrogram_types.InlineKeyboardMarkup.read(reply_markup)
|
|
||||||
elif isinstance(reply_markup, types.ReplyKeyboardHide):
|
|
||||||
reply_markup = pyrogram_types.ReplyKeyboardRemove.read(reply_markup)
|
|
||||||
else:
|
|
||||||
reply_markup = None
|
|
||||||
|
|
||||||
m = pyrogram_types.Message(
|
|
||||||
message_id=message.id,
|
|
||||||
date=message.date,
|
|
||||||
chat=parse_chat(message, users, chats),
|
|
||||||
from_user=parse_user(users.get(message.from_id, None)),
|
|
||||||
text=message.message or None if media is None else None,
|
|
||||||
caption=message.message or None if media is not None else None,
|
|
||||||
entities=entities or None if media is None else None,
|
|
||||||
caption_entities=entities or None if media is not None else None,
|
|
||||||
author_signature=message.post_author,
|
|
||||||
forward_from=forward_from,
|
|
||||||
forward_from_chat=forward_from_chat,
|
|
||||||
forward_from_message_id=forward_from_message_id,
|
|
||||||
forward_signature=forward_signature,
|
|
||||||
forward_date=forward_date,
|
|
||||||
edit_date=message.edit_date,
|
|
||||||
media_group_id=message.grouped_id,
|
|
||||||
photo=photo,
|
|
||||||
location=location,
|
|
||||||
contact=contact,
|
|
||||||
venue=venue,
|
|
||||||
audio=audio,
|
|
||||||
voice=voice,
|
|
||||||
video=video,
|
|
||||||
video_note=video_note,
|
|
||||||
sticker=sticker,
|
|
||||||
document=document,
|
|
||||||
views=message.views,
|
|
||||||
via_bot=parse_user(users.get(message.via_bot_id, None)),
|
|
||||||
outgoing=message.out,
|
|
||||||
client=proxy(client),
|
|
||||||
reply_markup=reply_markup
|
|
||||||
)
|
|
||||||
|
|
||||||
if message.reply_to_msg_id and replies:
|
|
||||||
m.reply_to_message = client.get_messages(m.chat.id, message.reply_to_msg_id, replies=replies - 1)
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
|
|
||||||
def parse_message_service(
|
|
||||||
client,
|
|
||||||
message: types.MessageService,
|
|
||||||
users: dict,
|
|
||||||
chats: dict
|
|
||||||
) -> pyrogram_types.Message:
|
|
||||||
action = message.action
|
|
||||||
|
|
||||||
new_chat_members = None
|
|
||||||
left_chat_member = None
|
|
||||||
new_chat_title = None
|
|
||||||
delete_chat_photo = None
|
|
||||||
migrate_to_chat_id = None
|
|
||||||
migrate_from_chat_id = None
|
|
||||||
group_chat_created = None
|
|
||||||
channel_chat_created = None
|
|
||||||
new_chat_photo = None
|
|
||||||
|
|
||||||
if isinstance(action, types.MessageActionChatAddUser):
|
|
||||||
new_chat_members = [parse_user(users[i]) for i in action.users]
|
|
||||||
elif isinstance(action, types.MessageActionChatJoinedByLink):
|
|
||||||
new_chat_members = [parse_user(users[message.from_id])]
|
|
||||||
elif isinstance(action, types.MessageActionChatDeleteUser):
|
|
||||||
left_chat_member = parse_user(users[action.user_id])
|
|
||||||
elif isinstance(action, types.MessageActionChatEditTitle):
|
|
||||||
new_chat_title = action.title
|
|
||||||
elif isinstance(action, types.MessageActionChatDeletePhoto):
|
|
||||||
delete_chat_photo = True
|
|
||||||
elif isinstance(action, types.MessageActionChatMigrateTo):
|
|
||||||
migrate_to_chat_id = action.channel_id
|
|
||||||
elif isinstance(action, types.MessageActionChannelMigrateFrom):
|
|
||||||
migrate_from_chat_id = action.chat_id
|
|
||||||
elif isinstance(action, types.MessageActionChatCreate):
|
|
||||||
group_chat_created = True
|
|
||||||
elif isinstance(action, types.MessageActionChannelCreate):
|
|
||||||
channel_chat_created = True
|
|
||||||
elif isinstance(action, types.MessageActionChatEditPhoto):
|
|
||||||
photo = action.photo
|
|
||||||
|
|
||||||
if isinstance(photo, types.Photo):
|
|
||||||
sizes = photo.sizes
|
|
||||||
photo_sizes = []
|
|
||||||
|
|
||||||
for size in sizes:
|
|
||||||
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
|
||||||
loc = size.location
|
|
||||||
|
|
||||||
if isinstance(size, types.PhotoSize):
|
|
||||||
file_size = size.size
|
|
||||||
else:
|
|
||||||
file_size = len(size.bytes)
|
|
||||||
|
|
||||||
if isinstance(loc, types.FileLocation):
|
|
||||||
photo_size = pyrogram_types.PhotoSize(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi",
|
|
||||||
2,
|
|
||||||
loc.dc_id,
|
|
||||||
photo.id,
|
|
||||||
photo.access_hash,
|
|
||||||
loc.volume_id,
|
|
||||||
loc.secret,
|
|
||||||
loc.local_id
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=size.w,
|
|
||||||
height=size.h,
|
|
||||||
file_size=file_size,
|
|
||||||
date=photo.date
|
|
||||||
)
|
|
||||||
|
|
||||||
photo_sizes.append(photo_size)
|
|
||||||
|
|
||||||
new_chat_photo = photo_sizes
|
|
||||||
|
|
||||||
m = pyrogram_types.Message(
|
|
||||||
message_id=message.id,
|
|
||||||
date=message.date,
|
|
||||||
chat=parse_chat(message, users, chats),
|
|
||||||
from_user=parse_user(users.get(message.from_id, None)),
|
|
||||||
new_chat_members=new_chat_members,
|
|
||||||
left_chat_member=left_chat_member,
|
|
||||||
new_chat_title=new_chat_title,
|
|
||||||
new_chat_photo=new_chat_photo,
|
|
||||||
delete_chat_photo=delete_chat_photo,
|
|
||||||
migrate_to_chat_id=int("-100" + str(migrate_to_chat_id)) if migrate_to_chat_id else None,
|
|
||||||
migrate_from_chat_id=-migrate_from_chat_id if migrate_from_chat_id else None,
|
|
||||||
group_chat_created=group_chat_created,
|
|
||||||
channel_chat_created=channel_chat_created,
|
|
||||||
client=proxy(client)
|
|
||||||
# TODO: supergroup_chat_created
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(action, types.MessageActionPinMessage):
|
|
||||||
m.pinned_message = client.get_messages(m.chat.id, message.reply_to_msg_id, replies=0)
|
|
||||||
|
|
||||||
return m
|
|
||||||
|
|
||||||
|
|
||||||
def parse_message_empty(
|
|
||||||
client,
|
|
||||||
message: types.MessageEmpty
|
|
||||||
) -> pyrogram_types.Message:
|
|
||||||
return pyrogram_types.Message(message_id=message.id, client=proxy(client))
|
|
||||||
|
|
||||||
|
|
||||||
def get_peer_id(input_peer) -> int:
|
|
||||||
return (
|
|
||||||
input_peer.user_id if isinstance(input_peer, types.InputPeerUser)
|
|
||||||
else -input_peer.chat_id if isinstance(input_peer, types.InputPeerChat)
|
|
||||||
else int("-100" + str(input_peer.channel_id))
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_input_peer(peer_id: int, access_hash: int):
|
|
||||||
return (
|
|
||||||
types.InputPeerUser(peer_id, access_hash) if peer_id > 0
|
|
||||||
else types.InputPeerChannel(int(str(peer_id)[4:]), access_hash)
|
|
||||||
if (str(peer_id).startswith("-100") and access_hash)
|
|
||||||
else types.InputPeerChat(-peer_id)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def get_offset_date(dialogs):
|
|
||||||
for m in reversed(dialogs.messages):
|
|
||||||
if isinstance(m, types.MessageEmpty):
|
|
||||||
continue
|
|
||||||
else:
|
|
||||||
return m.date
|
|
||||||
else:
|
|
||||||
return 0
|
|
||||||
|
|
||||||
|
|
||||||
def parse_photos(photos):
|
|
||||||
if isinstance(photos, types.photos.Photos):
|
|
||||||
total_count = len(photos.photos)
|
|
||||||
else:
|
|
||||||
total_count = photos.count
|
|
||||||
|
|
||||||
user_profile_photos = []
|
|
||||||
|
|
||||||
for photo in photos.photos:
|
|
||||||
if isinstance(photo, types.Photo):
|
|
||||||
sizes = photo.sizes
|
|
||||||
photo_sizes = []
|
|
||||||
|
|
||||||
for size in sizes:
|
|
||||||
if isinstance(size, (types.PhotoSize, types.PhotoCachedSize)):
|
|
||||||
loc = size.location
|
|
||||||
|
|
||||||
if isinstance(size, types.PhotoSize):
|
|
||||||
file_size = size.size
|
|
||||||
else:
|
|
||||||
file_size = len(size.bytes)
|
|
||||||
|
|
||||||
if isinstance(loc, types.FileLocation):
|
|
||||||
photo_size = pyrogram_types.PhotoSize(
|
|
||||||
file_id=encode(
|
|
||||||
pack(
|
|
||||||
"<iiqqqqi",
|
|
||||||
2,
|
|
||||||
loc.dc_id,
|
|
||||||
photo.id,
|
|
||||||
photo.access_hash,
|
|
||||||
loc.volume_id,
|
|
||||||
loc.secret,
|
|
||||||
loc.local_id
|
|
||||||
)
|
|
||||||
),
|
|
||||||
width=size.w,
|
|
||||||
height=size.h,
|
|
||||||
file_size=file_size,
|
|
||||||
date=photo.date
|
|
||||||
)
|
|
||||||
|
|
||||||
photo_sizes.append(photo_size)
|
|
||||||
|
|
||||||
user_profile_photos.append(photo_sizes)
|
|
||||||
|
|
||||||
return pyrogram_types.UserProfilePhotos(
|
|
||||||
total_count=total_count,
|
|
||||||
photos=user_profile_photos
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_callback_query(client, callback_query, users):
|
|
||||||
peer = callback_query.peer
|
|
||||||
|
|
||||||
if isinstance(peer, types.PeerUser):
|
|
||||||
peer_id = peer.user_id
|
|
||||||
elif isinstance(peer, types.PeerChat):
|
|
||||||
peer_id = -peer.chat_id
|
|
||||||
else:
|
|
||||||
peer_id = int("-100" + str(peer.channel_id))
|
|
||||||
|
|
||||||
return pyrogram_types.CallbackQuery(
|
|
||||||
id=callback_query.query_id,
|
|
||||||
from_user=parse_user(users[callback_query.user_id]),
|
|
||||||
message=client.get_messages(peer_id, callback_query.msg_id),
|
|
||||||
chat_instance=str(callback_query.chat_instance),
|
|
||||||
data=callback_query.data.decode(),
|
|
||||||
game_short_name=callback_query.game_short_name
|
|
||||||
# TODO: add inline_message_id
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def parse_chat_full(
|
|
||||||
client,
|
|
||||||
chat_full: types.messages.ChatFull or types.UserFull
|
|
||||||
) -> pyrogram_types.Chat:
|
|
||||||
if isinstance(chat_full, types.UserFull):
|
|
||||||
chat = parse_user_chat(chat_full.user)
|
|
||||||
chat.description = chat_full.about
|
|
||||||
else:
|
|
||||||
full_chat = chat_full.full_chat
|
|
||||||
chat = None
|
|
||||||
|
|
||||||
for i in chat_full.chats:
|
|
||||||
if full_chat.id == i.id:
|
|
||||||
chat = i
|
|
||||||
|
|
||||||
if isinstance(full_chat, types.ChatFull):
|
|
||||||
chat = parse_chat_chat(chat)
|
|
||||||
else:
|
|
||||||
chat = parse_channel_chat(chat)
|
|
||||||
chat.description = full_chat.about or None
|
|
||||||
# TODO: Add StickerSet type
|
|
||||||
chat.can_set_sticker_set = full_chat.can_set_stickers
|
|
||||||
chat.sticker_set_name = full_chat.stickerset
|
|
||||||
|
|
||||||
if full_chat.pinned_msg_id:
|
|
||||||
chat.pinned_message = client.get_messages(
|
|
||||||
int("-100" + str(full_chat.id)),
|
|
||||||
full_chat.pinned_msg_id
|
|
||||||
)
|
|
||||||
|
|
||||||
if isinstance(full_chat.exported_invite, types.ChatInviteExported):
|
|
||||||
chat.invite_link = full_chat.exported_invite.link
|
|
||||||
|
|
||||||
return chat
|
|
Loading…
x
Reference in New Issue
Block a user