mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2025-12-29 12:04:51 +00:00
Compare commits
6 commits
9fd572d8a2
...
fb7d5a46a2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fb7d5a46a2 | ||
|
|
8b2ae07ea0 | ||
|
|
62dd3c51ba | ||
|
|
b414831b72 | ||
|
|
a5698e73a9 | ||
|
|
98ae2bee64 |
29 changed files with 510 additions and 156 deletions
|
|
@ -442,12 +442,12 @@ def start(format: bool = False):
|
|||
references, count = get_references(c.qualname, "constructors")
|
||||
|
||||
if references:
|
||||
docstring += f"\n Functions:\n This object can be returned by " \
|
||||
docstring += "\n Functions:\n This object can be returned by " \
|
||||
f"{count} function{'s' if count > 1 else ''}.\n\n" \
|
||||
f" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
||||
f" .. autosummary::\n" \
|
||||
f" :nosignatures:\n\n" \
|
||||
f" " + references
|
||||
" .. currentmodule:: pyrogram.raw.functions\n\n" \
|
||||
" .. autosummary::\n" \
|
||||
" :nosignatures:\n\n" \
|
||||
" " + references
|
||||
|
||||
write_types = read_types = "" if c.has_flags else "# No flags\n "
|
||||
|
||||
|
|
|
|||
|
|
@ -524,6 +524,7 @@ def pyrogram_api():
|
|||
Audio
|
||||
AvailableEffect
|
||||
Document
|
||||
ExternalReplyInfo
|
||||
AlternativeVideo
|
||||
Animation
|
||||
Video
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ from pygments.styles.friendly import FriendlyStyle
|
|||
FriendlyStyle.background_color = "#f3f2f1"
|
||||
|
||||
project = "Pyrofork"
|
||||
copyright = f"2022-present, Mayuri-Chan"
|
||||
copyright = "2022-present, Mayuri-Chan"
|
||||
author = "Mayuri-Chan"
|
||||
|
||||
version = ".".join(__version__.split(".")[:-1])
|
||||
|
|
|
|||
|
|
@ -17,13 +17,17 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from concurrent.futures.thread import ThreadPoolExecutor
|
||||
|
||||
from . import raw, types, filters, handlers, emoji, enums
|
||||
from .client import Client
|
||||
from .sync import idle, compose
|
||||
|
||||
__fork_name__ = "PyroFork"
|
||||
__version__ = "2.3.59"
|
||||
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
|
||||
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"
|
||||
|
||||
from concurrent.futures.thread import ThreadPoolExecutor
|
||||
|
||||
|
||||
class StopTransmission(Exception):
|
||||
pass
|
||||
|
|
@ -36,9 +40,20 @@ class StopPropagation(StopAsyncIteration):
|
|||
class ContinuePropagation(StopAsyncIteration):
|
||||
pass
|
||||
|
||||
|
||||
from . import raw, types, filters, handlers, emoji, enums
|
||||
from .client import Client
|
||||
from .sync import idle, compose
|
||||
|
||||
crypto_executor = ThreadPoolExecutor(1, thread_name_prefix="CryptoWorker")
|
||||
|
||||
__all__ = [
|
||||
"Client",
|
||||
"idle",
|
||||
"compose",
|
||||
"crypto_executor",
|
||||
"StopTransmission",
|
||||
"StopPropagation",
|
||||
"ContinuePropagation",
|
||||
"raw",
|
||||
"types",
|
||||
"filters",
|
||||
"handlers",
|
||||
"emoji",
|
||||
"enums",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ from importlib import import_module
|
|||
from io import StringIO, BytesIO
|
||||
from mimetypes import MimeTypes
|
||||
from pathlib import Path
|
||||
from typing import Union, List, Optional, Callable, AsyncGenerator, Type, Tuple
|
||||
from typing import Union, List, Optional, Callable, AsyncGenerator, Tuple
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import __version__, __license__
|
||||
|
|
@ -51,24 +51,26 @@ from pyrogram.handlers.handler import Handler
|
|||
from pyrogram.methods import Methods
|
||||
from pyrogram.session import Auth, Session
|
||||
from pyrogram.storage import FileStorage, MemoryStorage, Storage
|
||||
from pyrogram.types import User, TermsOfService
|
||||
from pyrogram.utils import ainput
|
||||
from .connection import Connection
|
||||
from .connection.transport import TCPAbridged
|
||||
from .dispatcher import Dispatcher
|
||||
from .file_id import FileId, FileType, ThumbnailSource
|
||||
from .mime_types import mime_types
|
||||
from .parser import Parser
|
||||
from .session.internals import MsgId
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
MONGO_AVAIL = False
|
||||
|
||||
try:
|
||||
import pymongo
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
from pyrogram.storage import MongoStorage
|
||||
from pyrogram.types import User, TermsOfService
|
||||
from pyrogram.utils import ainput
|
||||
from .connection import Connection
|
||||
from .connection.transport import TCP, TCPAbridged
|
||||
from .dispatcher import Dispatcher
|
||||
from .file_id import FileId, FileType, ThumbnailSource
|
||||
from .filters import Filter
|
||||
from .mime_types import mime_types
|
||||
from .parser import Parser
|
||||
from .session.internals import MsgId
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
MONGO_AVAIL = True
|
||||
|
||||
|
||||
class Client(Methods):
|
||||
|
|
@ -316,9 +318,7 @@ class Client(Methods):
|
|||
elif self.in_memory:
|
||||
self.storage = MemoryStorage(self.name)
|
||||
elif self.mongodb:
|
||||
try:
|
||||
import pymongo
|
||||
except Exception:
|
||||
if not MONGO_AVAIL:
|
||||
log.warning(
|
||||
"pymongo is missing! "
|
||||
"Using MemoryStorage as session storage"
|
||||
|
|
@ -953,7 +953,7 @@ class Client(Methods):
|
|||
)
|
||||
|
||||
count += 1
|
||||
except Exception as e:
|
||||
except Exception:
|
||||
pass
|
||||
else:
|
||||
for path, handlers in include:
|
||||
|
|
|
|||
|
|
@ -23,3 +23,13 @@ from .tcp_abridged_o import TCPAbridgedO
|
|||
from .tcp_full import TCPFull
|
||||
from .tcp_intermediate import TCPIntermediate
|
||||
from .tcp_intermediate_o import TCPIntermediateO
|
||||
|
||||
__all__ = [
|
||||
"TCP",
|
||||
"Proxy",
|
||||
"TCPAbridged",
|
||||
"TCPAbridgedO",
|
||||
"TCPFull",
|
||||
"TCPIntermediate",
|
||||
"TCPIntermediateO"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -71,7 +71,7 @@ def unpack(
|
|||
message = Message.read(data)
|
||||
except KeyError as e:
|
||||
if e.args[0] == 0:
|
||||
raise ConnectionError(f"Received empty data. Check your internet connection.")
|
||||
raise ConnectionError("Received empty data. Check your internet connection.")
|
||||
|
||||
left = data.read().hex()
|
||||
|
||||
|
|
@ -79,7 +79,7 @@ def unpack(
|
|||
left = [[left[i:i + 8] for i in range(0, len(left), 8)] for left in left]
|
||||
left = "\n".join(" ".join(x for x in left) for left in left)
|
||||
|
||||
raise ValueError(f"The server sent an unknown constructor: {hex(e.args[0])}\n{left}")
|
||||
raise ValueError("The server sent an unknown constructor: {hex(e.args[0])}\n{left}")
|
||||
|
||||
# https://core.telegram.org/mtproto/security_guidelines#checking-sha256-hash-value-of-msg-key
|
||||
# 96 = 88 + 8 (incoming message)
|
||||
|
|
|
|||
|
|
@ -42,3 +42,31 @@ from .message_reaction_updated_handler import MessageReactionUpdatedHandler
|
|||
from .message_reaction_count_updated_handler import MessageReactionCountUpdatedHandler
|
||||
from .pre_checkout_query_handler import PreCheckoutQueryHandler
|
||||
from .shipping_query_handler import ShippingQueryHandler
|
||||
|
||||
__all__ = [
|
||||
"BotBusinessConnectHandler",
|
||||
"BotBusinessMessageHandler",
|
||||
"CallbackQueryHandler",
|
||||
"ChatJoinRequestHandler",
|
||||
"ChatMemberUpdatedHandler",
|
||||
"ConversationHandler",
|
||||
"ChosenInlineResultHandler",
|
||||
"DeletedMessagesHandler",
|
||||
"DeletedBotBusinessMessagesHandler",
|
||||
"DisconnectHandler",
|
||||
"EditedMessageHandler",
|
||||
"EditedBotBusinessMessageHandler",
|
||||
"ErrorHandler",
|
||||
"InlineQueryHandler",
|
||||
"MessageHandler",
|
||||
"PollHandler",
|
||||
"PreCheckoutQueryHandler",
|
||||
"PurchasedPaidMediaHandler",
|
||||
"RawUpdateHandler",
|
||||
"UserStatusHandler",
|
||||
"StoryHandler",
|
||||
"MessageReactionUpdatedHandler",
|
||||
"MessageReactionCountUpdatedHandler",
|
||||
"PreCheckoutQueryHandler",
|
||||
"ShippingQueryHandler",
|
||||
]
|
||||
|
|
|
|||
|
|
@ -101,9 +101,9 @@ def kb(rows=None, **kwargs):
|
|||
line = []
|
||||
for button in row:
|
||||
button_type = type(button)
|
||||
if button_type == str:
|
||||
if isinstance(button_type, str):
|
||||
button = KeyboardButton(button)
|
||||
elif button_type == dict:
|
||||
elif isinstance(button_type, dict):
|
||||
button = KeyboardButton(**button)
|
||||
|
||||
line.append(button)
|
||||
|
|
|
|||
|
|
@ -17,7 +17,6 @@
|
|||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
import pyrogram
|
||||
from pyrogram import raw
|
||||
from pyrogram import types
|
||||
from typing import Union
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Callable, Optional, Union
|
||||
from typing import Callable
|
||||
|
||||
import pyrogram
|
||||
from pyrogram.filters import Filter
|
||||
|
|
|
|||
|
|
@ -180,8 +180,12 @@ class CopyMediaGroup:
|
|||
**await self.parser.parse(
|
||||
captions[i] if isinstance(captions, list) and i < len(captions) and captions[i] else
|
||||
captions if isinstance(captions, str) and i == 0 else
|
||||
message.caption if message.caption and message.caption != "None" and not type(
|
||||
captions) is str else "")
|
||||
message.caption if (
|
||||
message.caption
|
||||
and message.caption != "None"
|
||||
and not isinstance(captions, str)
|
||||
) else ""
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,6 @@
|
|||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import html
|
||||
import logging
|
||||
import re
|
||||
from typing import Optional
|
||||
|
||||
|
|
|
|||
|
|
@ -30,3 +30,24 @@ from .primitives.int import Int, Long, Int128, Int256
|
|||
from .primitives.string import String
|
||||
from .primitives.vector import Vector
|
||||
from .tl_object import TLObject
|
||||
|
||||
__all__ = [
|
||||
"FutureSalt",
|
||||
"FutureSalts",
|
||||
"GzipPacked",
|
||||
"List",
|
||||
"Message",
|
||||
"MsgContainer",
|
||||
"Bool",
|
||||
"BoolFalse",
|
||||
"BoolTrue",
|
||||
"Bytes",
|
||||
"Double",
|
||||
"Int",
|
||||
"Long",
|
||||
"Int128",
|
||||
"Int256",
|
||||
"String",
|
||||
"Vector",
|
||||
"TLObject"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -20,3 +20,9 @@
|
|||
from .data_center import DataCenter
|
||||
from .msg_factory import MsgFactory
|
||||
from .msg_id import MsgId
|
||||
|
||||
__all__ = [
|
||||
"DataCenter",
|
||||
"MsgFactory",
|
||||
"MsgId"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -30,3 +30,8 @@ from .update import *
|
|||
from .user_and_chats import *
|
||||
from .payments import *
|
||||
from .pyromod import *
|
||||
|
||||
__all__ = [
|
||||
"List",
|
||||
"Object"
|
||||
]
|
||||
|
|
|
|||
|
|
@ -18,8 +18,7 @@
|
|||
|
||||
from typing import List
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import raw, types, utils
|
||||
from pyrogram import raw, types
|
||||
|
||||
from ..object import Object
|
||||
|
||||
|
|
|
|||
|
|
@ -17,14 +17,11 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union, List, Match, Optional
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import raw, enums
|
||||
from pyrogram import types
|
||||
from pyrogram import raw, types
|
||||
from ..object import Object
|
||||
from ..update import Update
|
||||
from ... import utils
|
||||
|
||||
|
||||
class PreCheckoutQuery(Object, Update):
|
||||
|
|
@ -76,7 +73,11 @@ class PreCheckoutQuery(Object, Update):
|
|||
self.payment_info = payment_info
|
||||
|
||||
@staticmethod
|
||||
async def _parse(client: "pyrogram.Client", pre_checkout_query, users) -> "PreCheckoutQuery":
|
||||
async def _parse(
|
||||
client: "pyrogram.Client",
|
||||
pre_checkout_query: "raw.types.UpdateBotPrecheckoutQuery",
|
||||
users
|
||||
) -> "PreCheckoutQuery":
|
||||
# Try to decode pre-checkout query payload into string. If that fails, fallback to bytes instead of decoding by
|
||||
# ignoring/replacing errors, this way, button clicks will still work.
|
||||
try:
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
|
|
@ -16,8 +17,6 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Union, Optional
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import raw, types
|
||||
|
||||
|
|
@ -49,14 +48,14 @@ class ShippingQuery(Object, Update):
|
|||
client: "pyrogram.Client" = None,
|
||||
id: str,
|
||||
from_user: "types.User",
|
||||
invoice_payload: str,
|
||||
payload: str,
|
||||
shipping_address: "types.ShippingAddress" = None
|
||||
):
|
||||
super().__init__(client)
|
||||
|
||||
self.id = id
|
||||
self.from_user = from_user
|
||||
self.invoice_payload = invoice_payload
|
||||
self.payload = payload
|
||||
self.shipping_address = shipping_address
|
||||
|
||||
@staticmethod
|
||||
|
|
@ -72,19 +71,12 @@ class ShippingQuery(Object, Update):
|
|||
except (UnicodeDecodeError, AttributeError):
|
||||
payload = shipping_query.payload
|
||||
|
||||
return types.PreCheckoutQuery(
|
||||
id=str(shipping_query.query_id),
|
||||
from_user=types.User._parse(client, users[shipping_query.user_id]),
|
||||
invoice_payload=payload,
|
||||
shipping_address=types.ShippingAddress(
|
||||
country_code=shipping_query.shipping_address.country_iso2,
|
||||
state=shipping_query.shipping_address.state,
|
||||
city=shipping_query.shipping_address.city,
|
||||
street_line1=shipping_query.shipping_address.street_line1,
|
||||
street_line2=shipping_query.shipping_address.street_line2,
|
||||
post_code=shipping_query.shipping_address.post_code
|
||||
),
|
||||
client=client
|
||||
return ShippingQuery(
|
||||
client=client,
|
||||
id=shipping_query.query_id,
|
||||
from_user=types.User._parse(client, shipping_query.user_id, users),
|
||||
payload=payload,
|
||||
shipping_address=types.ShippingAddress._parse(client, shipping_query.shipping_address)
|
||||
)
|
||||
|
||||
async def answer(
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ from .contact import Contact
|
|||
from .contact_registered import ContactRegistered
|
||||
from .dice import Dice
|
||||
from .document import Document
|
||||
from .external_reply_info import ExternalReplyInfo
|
||||
from .game import Game
|
||||
from .giveaway import Giveaway
|
||||
from .giveaway_launched import GiveawayLaunched
|
||||
|
|
@ -89,6 +90,7 @@ __all__ = [
|
|||
"Contact",
|
||||
"ContactRegistered",
|
||||
"Document",
|
||||
"ExternalReplyInfo",
|
||||
"Game",
|
||||
"Giveaway",
|
||||
"GiveawayLaunched",
|
||||
|
|
|
|||
319
pyrogram/types/messages_and_media/external_reply_info.py
Normal file
319
pyrogram/types/messages_and_media/external_reply_info.py
Normal file
|
|
@ -0,0 +1,319 @@
|
|||
# Pyrogram - Telegram MTProto API Client Library for Python
|
||||
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
|
||||
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||
#
|
||||
# This file is part of Pyrogram.
|
||||
#
|
||||
# Pyrogram is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Lesser General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Pyrogram is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import Dict, Optional
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import enums, raw, types, utils
|
||||
|
||||
from ..object import Object
|
||||
|
||||
|
||||
class ExternalReplyInfo(Object):
|
||||
"""This object contains information about a message that is being replied to, which may come from another chat or forum topic.
|
||||
|
||||
Parameters:
|
||||
origin (:obj:`~pyrogram.types.MessageOrigin`, *optional*):
|
||||
Origin of the message replied to by the given message.
|
||||
|
||||
chat (:obj:`~pyrogram.types.Chat`, *optional*):
|
||||
Chat the original message belongs to.
|
||||
Available only if the chat is a supergroup or a channel.
|
||||
|
||||
message_id (``int``, *optional*):
|
||||
Unique message identifier inside the original chat.
|
||||
Available only if the original chat is a supergroup or a channel.
|
||||
|
||||
media (:obj:`~pyrogram.enums.MessageMediaType`, *optional*):
|
||||
The message is a media message.
|
||||
This field will contain the enumeration type of the media message.
|
||||
You can use ``media = getattr(message, message.media.value)`` to access the media message.
|
||||
|
||||
animation (:obj:`~pyrogram.types.Animation`, *optional*):
|
||||
Message is an animation, information about the animation.
|
||||
|
||||
audio (:obj:`~pyrogram.types.Audio`, *optional*):
|
||||
Message is an audio file, information about the file.
|
||||
|
||||
document (:obj:`~pyrogram.types.Document`, *optional*):
|
||||
Message is a general file, information about the file.
|
||||
|
||||
paid_media (:obj:`~pyrogram.types.PaidMediaInfo`, *optional*):
|
||||
Message contains paid media; information about the paid media.
|
||||
|
||||
photo (:obj:`~pyrogram.types.Photo`, *optional*):
|
||||
Message is a photo, information about the photo.
|
||||
|
||||
sticker (:obj:`~pyrogram.types.Sticker`, *optional*):
|
||||
Message is a sticker, information about the sticker.
|
||||
|
||||
story (:obj:`~pyrogram.types.Story`, *optional*):
|
||||
Message is a forwarded story.
|
||||
|
||||
video (:obj:`~pyrogram.types.Video`, *optional*):
|
||||
Message is a video, information about the video.
|
||||
|
||||
video_note (:obj:`~pyrogram.types.VideoNote`, *optional*):
|
||||
Message is a video note, information about the video message.
|
||||
|
||||
voice (:obj:`~pyrogram.types.Voice`, *optional*):
|
||||
Message is a voice message, information about the file.
|
||||
|
||||
has_media_spoiler (``bool``, *optional*):
|
||||
True, if the message media is covered by a spoiler animation.
|
||||
|
||||
contact (:obj:`~pyrogram.types.Contact`, *optional*):
|
||||
Message is a shared contact, information about the contact.
|
||||
|
||||
dice (:obj:`~pyrogram.types.Dice`, *optional*):
|
||||
A dice containing a value that is randomly generated by Telegram.
|
||||
|
||||
game (:obj:`~pyrogram.types.Game`, *optional*):
|
||||
Message is a game, information about the game.
|
||||
|
||||
giveaway (:obj:`~pyrogram.types.Giveaway`, *optional*):
|
||||
Message is a scheduled giveaway, information about the giveaway.
|
||||
|
||||
giveaway_winners (:obj:`~pyrogram.types.GiveawayWinners`, *optional*):
|
||||
A giveaway with public winners was completed
|
||||
|
||||
invoice (:obj:`~pyrogram.types.Invoice`, *optional*):
|
||||
Message is a invoice, information about the invoice.
|
||||
`More about payments » <https://core.telegram.org/bots/api#payments>`_
|
||||
|
||||
location (:obj:`~pyrogram.types.Location`, *optional*):
|
||||
Message is a shared location, information about the location.
|
||||
|
||||
poll (:obj:`~pyrogram.types.Poll`, *optional*):
|
||||
Message is a native poll, information about the poll.
|
||||
|
||||
venue (:obj:`~pyrogram.types.Venue`, *optional*):
|
||||
Message is a venue, information about the venue.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
*,
|
||||
client: "pyrogram.Client" = None,
|
||||
origin: "types.MessageOrigin" = None,
|
||||
chat: "types.Chat" = None,
|
||||
message_id: int,
|
||||
media: Optional["enums.MessageMediaType"] = None,
|
||||
animation: Optional["types.Animation"] = None,
|
||||
audio: Optional["types.Audio"] = None,
|
||||
document: Optional["types.Document"] = None,
|
||||
paid_media: Optional["types.PaidMediaInfo"] = None,
|
||||
photo: Optional["types.Photo"] = None,
|
||||
sticker: Optional["types.Sticker"] = None,
|
||||
story: Optional["types.Story"] = None,
|
||||
video: Optional["types.Video"] = None,
|
||||
video_note: Optional["types.VideoNote"] = None,
|
||||
voice: Optional["types.Voice"] = None,
|
||||
has_media_spoiler: Optional[bool] = None,
|
||||
contact: Optional["types.Contact"] = None,
|
||||
dice: Optional["types.Dice"] = None,
|
||||
game: Optional["types.Game"] = None,
|
||||
giveaway: Optional["types.Giveaway"] = None,
|
||||
giveaway_winners: Optional["types.GiveawayWinners"] = None,
|
||||
invoice: Optional["types.Invoice"] = None,
|
||||
location: Optional["types.Location"] = None,
|
||||
poll: Optional["types.Poll"] = None,
|
||||
venue: Optional["types.Venue"] = None,
|
||||
):
|
||||
super().__init__(client)
|
||||
|
||||
self.origin = origin
|
||||
self.chat = chat
|
||||
self.message_id = message_id
|
||||
self.media = media
|
||||
self.animation = animation
|
||||
self.audio = audio
|
||||
self.document = document
|
||||
self.paid_media = paid_media
|
||||
self.photo = photo
|
||||
self.sticker = sticker
|
||||
self.story = story
|
||||
self.video = video
|
||||
self.video_note = video_note
|
||||
self.voice = voice
|
||||
self.has_media_spoiler = has_media_spoiler
|
||||
self.contact = contact
|
||||
self.dice = dice
|
||||
self.game = game
|
||||
self.giveaway = giveaway
|
||||
self.giveaway_winners = giveaway_winners
|
||||
self.invoice = invoice
|
||||
self.location = location
|
||||
self.poll = poll
|
||||
self.venue = venue
|
||||
|
||||
@staticmethod
|
||||
async def _parse(
|
||||
client,
|
||||
reply: "raw.types.MessageReplyHeader",
|
||||
users: Dict[int, "raw.types.User"],
|
||||
chats: Dict[int, "raw.types.Chat"],
|
||||
) -> Optional["ExternalReplyInfo"]:
|
||||
if not isinstance(reply, raw.types.MessageReplyHeader):
|
||||
return None
|
||||
|
||||
if not reply.reply_from:
|
||||
return None
|
||||
|
||||
animation = None
|
||||
audio = None
|
||||
document = None
|
||||
paid_media = None
|
||||
photo = None
|
||||
sticker = None
|
||||
story = None
|
||||
video = None
|
||||
video_note = None
|
||||
voice = None
|
||||
contact = None
|
||||
dice = None
|
||||
game = None
|
||||
giveaway = None
|
||||
giveaway_winners = None
|
||||
invoice = None
|
||||
location = None
|
||||
poll = None
|
||||
venue = None
|
||||
|
||||
media = reply.reply_media
|
||||
media_type = None
|
||||
has_media_spoiler = None
|
||||
|
||||
if media:
|
||||
if isinstance(media, raw.types.MessageMediaPhoto):
|
||||
photo = types.Photo._parse(client, media.photo, media.ttl_seconds)
|
||||
media_type = enums.MessageMediaType.PHOTO
|
||||
has_media_spoiler = media.spoiler
|
||||
elif isinstance(media, raw.types.MessageMediaGeo):
|
||||
location = types.Location._parse(client, media.geo)
|
||||
media_type = enums.MessageMediaType.LOCATION
|
||||
elif isinstance(media, raw.types.MessageMediaContact):
|
||||
contact = types.Contact._parse(client, media)
|
||||
media_type = enums.MessageMediaType.CONTACT
|
||||
elif isinstance(media, raw.types.MessageMediaVenue):
|
||||
venue = types.Venue._parse(client, media)
|
||||
media_type = enums.MessageMediaType.VENUE
|
||||
elif isinstance(media, raw.types.MessageMediaGame):
|
||||
game = types.Game._parse(client, media)
|
||||
media_type = enums.MessageMediaType.GAME
|
||||
elif isinstance(media, raw.types.MessageMediaGiveaway):
|
||||
giveaway = types.Giveaway._parse(client, media, chats)
|
||||
media_type = enums.MessageMediaType.GIVEAWAY
|
||||
elif isinstance(media, raw.types.MessageMediaGiveawayResults):
|
||||
giveaway_winners = await types.GiveawayWinners._parse(client, media, users, chats)
|
||||
media_type = enums.MessageMediaType.GIVEAWAY_WINNERS
|
||||
elif isinstance(media, raw.types.MessageMediaInvoice):
|
||||
invoice = types.Invoice._parse(media)
|
||||
media_type = enums.MessageMediaType.INVOICE
|
||||
elif isinstance(media, raw.types.MessageMediaStory):
|
||||
story = await types.Story._parse(client, media, media.peer, users, chats)
|
||||
media_type = enums.MessageMediaType.STORY
|
||||
elif isinstance(media, raw.types.MessageMediaDocument):
|
||||
doc = media.document
|
||||
|
||||
if isinstance(doc, raw.types.Document):
|
||||
attributes = {type(i): i for i in doc.attributes}
|
||||
|
||||
file_name = getattr(
|
||||
attributes.get(
|
||||
raw.types.DocumentAttributeFilename, None
|
||||
), "file_name", None
|
||||
)
|
||||
|
||||
if raw.types.DocumentAttributeAnimated in attributes:
|
||||
video_attributes = attributes.get(raw.types.DocumentAttributeVideo, None)
|
||||
animation = types.Animation._parse(client, doc, video_attributes, file_name)
|
||||
media_type = enums.MessageMediaType.ANIMATION
|
||||
has_media_spoiler = media.spoiler
|
||||
elif raw.types.DocumentAttributeSticker in attributes:
|
||||
sticker = await types.Sticker._parse(client, doc, attributes)
|
||||
media_type = enums.MessageMediaType.STICKER
|
||||
elif raw.types.DocumentAttributeVideo in attributes:
|
||||
video_attributes = attributes[raw.types.DocumentAttributeVideo]
|
||||
|
||||
if video_attributes.round_message:
|
||||
video_note = types.VideoNote._parse(client, doc, video_attributes, media.ttl_seconds)
|
||||
media_type = enums.MessageMediaType.VIDEO_NOTE
|
||||
else:
|
||||
video = types.Video._parse(client, doc, video_attributes, file_name, media.ttl_seconds, media.video_cover, media.video_timestamp, media.alt_documents)
|
||||
media_type = enums.MessageMediaType.VIDEO
|
||||
has_media_spoiler = media.spoiler
|
||||
elif raw.types.DocumentAttributeAudio in attributes:
|
||||
audio_attributes = attributes[raw.types.DocumentAttributeAudio]
|
||||
|
||||
if audio_attributes.voice:
|
||||
voice = types.Voice._parse(client, doc, audio_attributes, media.ttl_seconds)
|
||||
media_type = enums.MessageMediaType.VOICE
|
||||
else:
|
||||
audio = types.Audio._parse(client, doc, audio_attributes, file_name)
|
||||
media_type = enums.MessageMediaType.AUDIO
|
||||
else:
|
||||
document = types.Document._parse(client, doc, file_name)
|
||||
media_type = enums.MessageMediaType.DOCUMENT
|
||||
elif isinstance(media, raw.types.MessageMediaPoll):
|
||||
poll = types.Poll._parse(client, media, users)
|
||||
media_type = enums.MessageMediaType.POLL
|
||||
elif isinstance(media, raw.types.MessageMediaDice):
|
||||
dice = types.Dice._parse(client, media)
|
||||
media_type = enums.MessageMediaType.DICE
|
||||
elif isinstance(media, raw.types.MessageMediaPaidMedia):
|
||||
paid_media = types.PaidMediaInfo._parse(client, media)
|
||||
media_type = enums.MessageMediaType.PAID_MEDIA
|
||||
else:
|
||||
media = None
|
||||
|
||||
return ExternalReplyInfo(
|
||||
origin=types.MessageOrigin._parse(
|
||||
client,
|
||||
reply.reply_from,
|
||||
users,
|
||||
chats,
|
||||
),
|
||||
chat=types.Chat._parse_chat(
|
||||
client,
|
||||
chats.get(utils.get_raw_peer_id(reply.reply_to_peer_id)),
|
||||
),
|
||||
message_id=reply.reply_to_msg_id,
|
||||
media=media_type,
|
||||
animation=animation,
|
||||
audio=audio,
|
||||
document=document,
|
||||
paid_media=paid_media,
|
||||
photo=photo,
|
||||
sticker=sticker,
|
||||
story=story,
|
||||
video=video,
|
||||
video_note=video_note,
|
||||
voice=voice,
|
||||
has_media_spoiler=has_media_spoiler,
|
||||
contact=contact,
|
||||
dice=dice,
|
||||
game=game,
|
||||
giveaway=giveaway,
|
||||
giveaway_winners=giveaway_winners,
|
||||
invoice=invoice,
|
||||
location=location,
|
||||
poll=poll,
|
||||
venue=venue
|
||||
)
|
||||
|
|
@ -69,12 +69,11 @@ class Game(Object):
|
|||
self.animation = animation
|
||||
|
||||
@staticmethod
|
||||
def _parse(client, message: "raw.types.Message") -> "Game":
|
||||
game: "raw.types.Game" = message.media.game
|
||||
def _parse(client, media: "raw.types.MessageMediaGame") -> "Game":
|
||||
animation = None
|
||||
|
||||
if game.document:
|
||||
attributes = {type(i): i for i in game.document.attributes}
|
||||
if media.game.document:
|
||||
attributes = {type(i): i for i in media.game.document.attributes}
|
||||
|
||||
file_name = getattr(
|
||||
attributes.get(
|
||||
|
|
@ -84,17 +83,17 @@ class Game(Object):
|
|||
|
||||
animation = types.Animation._parse(
|
||||
client,
|
||||
game.document,
|
||||
media.game.document,
|
||||
attributes.get(raw.types.DocumentAttributeVideo, None),
|
||||
file_name
|
||||
)
|
||||
|
||||
return Game(
|
||||
id=game.id,
|
||||
title=game.title,
|
||||
short_name=game.short_name,
|
||||
description=game.description,
|
||||
photo=types.Photo._parse(client, game.photo),
|
||||
id=media.game.id,
|
||||
title=media.game.title,
|
||||
short_name=media.game.short_name,
|
||||
description=media.game.description,
|
||||
photo=types.Photo._parse(client, media.game.photo),
|
||||
animation=animation,
|
||||
client=client
|
||||
)
|
||||
|
|
|
|||
|
|
@ -73,7 +73,6 @@ class Giveaway(Object):
|
|||
stars: int = None,
|
||||
additional_price: str = None,
|
||||
allowed_countries: List[str] = None,
|
||||
private_channel_ids: List[int] = None,
|
||||
is_winners_hidden: bool = None
|
||||
):
|
||||
super().__init__(client)
|
||||
|
|
@ -86,28 +85,12 @@ class Giveaway(Object):
|
|||
self.new_subscribers = new_subscribers
|
||||
self.additional_price = additional_price
|
||||
self.allowed_countries = allowed_countries
|
||||
self.private_channel_ids = private_channel_ids
|
||||
self.is_winners_hidden = is_winners_hidden
|
||||
|
||||
@staticmethod
|
||||
async def _parse(client, message: "raw.types.Message") -> "Giveaway":
|
||||
async def _parse(client, message: "raw.types.Message", chats: dict) -> "Giveaway":
|
||||
giveaway: "raw.types.MessageMediaGiveaway" = message.media
|
||||
chats = []
|
||||
private_ids = []
|
||||
for raw_chat_id in giveaway.channels:
|
||||
chat_id = utils.get_channel_id(raw_chat_id)
|
||||
try:
|
||||
chat = await client.invoke(
|
||||
raw.functions.channels.GetChannels(
|
||||
id=[await client.resolve_peer(chat_id)]
|
||||
)
|
||||
)
|
||||
except FloodWait as e:
|
||||
await asyncio.sleep(e.value)
|
||||
except Exception:
|
||||
private_ids.append(chat_id)
|
||||
else:
|
||||
chats.append(types.Chat._parse_chat(client, chat.chats[0]))
|
||||
chats = types.List([types.Chat._parse_channel_chat(client, chats.get(i)) for i in giveaway.channels])
|
||||
|
||||
return Giveaway(
|
||||
chats=chats,
|
||||
|
|
@ -118,7 +101,6 @@ class Giveaway(Object):
|
|||
new_subscribers=giveaway.only_new_subscribers,
|
||||
additional_price=giveaway.prize_description,
|
||||
allowed_countries=giveaway.countries_iso2 if len(giveaway.countries_iso2) > 0 else None,
|
||||
private_channel_ids=private_ids if len(private_ids) > 0 else None,
|
||||
is_winners_hidden=not giveaway.winners_are_visible,
|
||||
client=client
|
||||
)
|
||||
|
|
|
|||
|
|
@ -318,6 +318,9 @@ class Message(Object, Update):
|
|||
Messages sent from yourself to other chats are outgoing (*outgoing* is True).
|
||||
An exception is made for your own personal chat; messages sent there will be incoming.
|
||||
|
||||
external_reply (:obj:`~pyrogram.types.ExternalReplyInfo`, *optional*):
|
||||
Information about the message that is being replied to, which may come from another chat or forum topic.
|
||||
|
||||
matches (List of regex Matches, *optional*):
|
||||
A list containing all `Match Objects <https://docs.python.org/3/library/re.html#match-objects>`_ that match
|
||||
the text of this message. Only applicable when using :obj:`Filters.regex <pyrogram.Filters.regex>`.
|
||||
|
|
@ -507,6 +510,7 @@ class Message(Object, Update):
|
|||
forwards: int = None,
|
||||
via_bot: "types.User" = None,
|
||||
outgoing: bool = None,
|
||||
external_reply: Optional["types.ExternalReplyInfo"] = None,
|
||||
matches: List[Match] = None,
|
||||
command: List[str] = None,
|
||||
bot_allowed: "types.BotAllowed" = None,
|
||||
|
|
@ -546,8 +550,8 @@ class Message(Object, Update):
|
|||
self.sender_business_bot = sender_business_bot
|
||||
self.date = date
|
||||
self.chat = chat
|
||||
self.topic = topic
|
||||
self.forward_origin = forward_origin
|
||||
self.external_reply = external_reply
|
||||
self.is_topic_message = is_topic_message
|
||||
self.reply_to_chat_id = reply_to_chat_id
|
||||
self.reply_to_message_id = reply_to_message_id
|
||||
|
|
@ -1032,10 +1036,10 @@ class Message(Object, Update):
|
|||
venue = types.Venue._parse(client, media)
|
||||
media_type = enums.MessageMediaType.VENUE
|
||||
elif isinstance(media, raw.types.MessageMediaGame):
|
||||
game = types.Game._parse(client, message)
|
||||
game = types.Game._parse(client, media)
|
||||
media_type = enums.MessageMediaType.GAME
|
||||
elif isinstance(media, raw.types.MessageMediaGiveaway):
|
||||
giveaway = await types.Giveaway._parse(client, message)
|
||||
giveaway = await types.Giveaway._parse(client, message, chats)
|
||||
media_type = enums.MessageMediaType.GIVEAWAY
|
||||
elif isinstance(media, raw.types.MessageMediaGiveawayResults):
|
||||
giveaway_result = await types.GiveawayResult._parse(client, message.media)
|
||||
|
|
@ -1221,6 +1225,12 @@ class Message(Object, Update):
|
|||
parsed_message.sender_chat = sender_chat
|
||||
|
||||
if message.reply_to:
|
||||
parsed_message.external_reply = await types.ExternalReplyInfo._parse(
|
||||
client,
|
||||
message.reply_to,
|
||||
users,
|
||||
chats
|
||||
)
|
||||
if isinstance(message.reply_to, raw.types.MessageReplyHeader):
|
||||
if message.reply_to.quote:
|
||||
parsed_message.quote = types.TextQuote._parse(
|
||||
|
|
@ -1263,20 +1273,15 @@ class Message(Object, Update):
|
|||
|
||||
if replies:
|
||||
if parsed_message.reply_to_message_id:
|
||||
if rtci is not None and parsed_message.chat.id != reply_to_chat_id:
|
||||
key = (reply_to_chat_id, message.reply_to.reply_to_msg_id)
|
||||
reply_to_params = {"chat_id": key[0], 'message_ids': key[1]}
|
||||
else:
|
||||
key = (parsed_message.chat.id, parsed_message.reply_to_message_id)
|
||||
reply_to_params = {'chat_id': key[0], 'reply_to_message_ids': message.id}
|
||||
|
||||
try:
|
||||
key = (parsed_message.chat.id, parsed_message.reply_to_message_id)
|
||||
reply_to_message = client.message_cache[key]
|
||||
|
||||
if not reply_to_message:
|
||||
reply_to_message = await client.get_messages(
|
||||
replies=replies - 1,
|
||||
**reply_to_params
|
||||
parsed_message.chat.id,
|
||||
reply_to_message_ids=message.id,
|
||||
replies=replies - 1
|
||||
)
|
||||
if reply_to_message and not reply_to_message.forum_topic_created:
|
||||
parsed_message.reply_to_message = reply_to_message
|
||||
|
|
|
|||
|
|
@ -16,11 +16,8 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
from typing import List, Optional, Union
|
||||
|
||||
import pyrogram
|
||||
from pyrogram import raw
|
||||
from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource
|
||||
from ..object import Object
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ class TranscribedAudio(Object):
|
|||
self.trial_remains_until_date = trial_remains_until_date
|
||||
|
||||
@staticmethod
|
||||
def _parse(transcribe_result: "raw.types.messages.TranscribedAudio") -> "TranscribeAudio":
|
||||
def _parse(transcribe_result: "raw.types.messages.TranscribedAudio") -> "TranscribedAudio":
|
||||
return TranscribedAudio(
|
||||
transcription_id=transcribe_result.transcription_id,
|
||||
text=transcribe_result.text,
|
||||
|
|
|
|||
|
|
@ -16,8 +16,6 @@
|
|||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import pyrogram
|
||||
|
||||
from pyrogram import raw
|
||||
from ..object import Object
|
||||
|
||||
|
|
|
|||
|
|
@ -121,9 +121,14 @@ async def parse_messages(
|
|||
|
||||
if replies:
|
||||
messages_with_replies = {
|
||||
i.id: i.reply_to
|
||||
i.id: i.reply_to.reply_to_msg_id
|
||||
for i in messages.messages
|
||||
if not isinstance(i, raw.types.MessageEmpty) and i.reply_to and isinstance(i.reply_to, raw.types.MessageReplyHeader)
|
||||
if (
|
||||
not isinstance(i, raw.types.MessageEmpty)
|
||||
and i.reply_to
|
||||
and isinstance(i.reply_to, raw.types.MessageReplyHeader)
|
||||
and i.reply_to.reply_to_msg_id is not None
|
||||
)
|
||||
}
|
||||
|
||||
message_reply_to_story = {
|
||||
|
|
@ -136,61 +141,27 @@ async def parse_messages(
|
|||
# We need a chat id, but some messages might be empty (no chat attribute available)
|
||||
# Scan until we find a message with a chat available (there must be one, because we are fetching replies)
|
||||
for m in parsed_messages:
|
||||
if not isinstance(m, types.Message):
|
||||
continue
|
||||
|
||||
if m.chat:
|
||||
chat_id = m.chat.id
|
||||
break
|
||||
else:
|
||||
chat_id = 0
|
||||
|
||||
is_all_within_chat = not any(
|
||||
value.reply_to_peer_id
|
||||
for value in messages_with_replies.values()
|
||||
reply_messages = await client.get_messages(
|
||||
chat_id,
|
||||
reply_to_message_ids=messages_with_replies.keys(),
|
||||
replies=replies - 1
|
||||
)
|
||||
reply_messages: List[pyrogram.types.Message] = []
|
||||
if is_all_within_chat:
|
||||
# fast path: fetch all messages within the same chat
|
||||
reply_messages = await client.get_messages(
|
||||
chat_id,
|
||||
reply_to_message_ids=messages_with_replies.keys(),
|
||||
replies=replies - 1
|
||||
)
|
||||
else:
|
||||
# slow path: fetch all messages individually
|
||||
for target_reply_to in messages_with_replies.values():
|
||||
to_be_added_msg = None
|
||||
the_chat_id = chat_id
|
||||
if target_reply_to.reply_to_peer_id:
|
||||
the_chat_id = get_channel_id(target_reply_to.reply_to_peer_id.channel_id)
|
||||
to_be_added_msg = await client.get_messages(
|
||||
chat_id=the_chat_id,
|
||||
message_ids=target_reply_to.reply_to_msg_id,
|
||||
replies=replies - 1
|
||||
)
|
||||
if isinstance(to_be_added_msg, list):
|
||||
for current_to_be_added in to_be_added_msg:
|
||||
reply_messages.append(current_to_be_added)
|
||||
elif to_be_added_msg:
|
||||
reply_messages.append(to_be_added_msg)
|
||||
|
||||
for message in parsed_messages:
|
||||
reply_to = messages_with_replies.get(message.id, None)
|
||||
if not reply_to:
|
||||
continue
|
||||
|
||||
reply_id = reply_to.reply_to_msg_id
|
||||
reply_id = messages_with_replies.get(message.id, None)
|
||||
|
||||
for reply in reply_messages:
|
||||
if reply.id == reply_id and not reply.forum_topic_created:
|
||||
message.reply_to_message = reply
|
||||
|
||||
if reply.id == reply_id:
|
||||
if not reply.forum_topic_created:
|
||||
message.reply_to_message = reply
|
||||
if message_reply_to_story:
|
||||
for m in parsed_messages:
|
||||
if not isinstance(m, types.Message):
|
||||
continue
|
||||
|
||||
if m.chat:
|
||||
chat_id = m.chat.id
|
||||
break
|
||||
|
|
@ -198,7 +169,7 @@ async def parse_messages(
|
|||
chat_id = 0
|
||||
|
||||
reply_messages = {}
|
||||
for msg_id in message_reply_to_story:
|
||||
for msg_id in message_reply_to_story.keys():
|
||||
reply_messages[msg_id] = await client.get_stories(
|
||||
message_reply_to_story[msg_id]['user_id'],
|
||||
message_reply_to_story[msg_id]['story_id']
|
||||
|
|
|
|||
Loading…
Reference in a new issue