Add ExternalReplyInfo

Signed-off-by: wulan17 <wulan17@nusantararom.org>
This commit is contained in:
KurimuzonAkuma 2025-03-21 19:57:45 +03:00 committed by wulan17
parent 5b9081cb08
commit d7e13e7b18
No known key found for this signature in database
GPG key ID: 318CD6CD3A6AC0A5
5 changed files with 348 additions and 12 deletions

View file

@ -524,6 +524,7 @@ def pyrogram_api():
Audio
AvailableEffect
Document
ExternalReplyInfo
AlternativeVideo
Animation
Video

View file

@ -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
@ -90,6 +91,7 @@ __all__ = [
"Contact",
"ContactRegistered",
"Document",
"ExternalReplyInfo",
"Game",
"Giveaway",
"GiveawayLaunched",

View file

@ -0,0 +1,324 @@
# Pyrogram - Telegram MTProto API Client Library for Python
# Copyright (C) 2017-present Dan <https://github.com/delivrance>
#
# This file is part of Pyrogram.
#
# Pyrogram is free software: you can redistribute it and/or modify
# it under the terms of the GNU Lesser General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Pyrogram is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Lesser General Public License for more details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with Pyrogram. If not, see <http://www.gnu.org/licenses/>.
from typing import 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.
link_preview_options (:obj:`~pyrogram.types.LinkPreviewOptions`, *optional*):
Options used for link preview generation for the original message, if it is a text message.
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,
link_preview_options: Optional["types.LinkPreviewOptions"] = None,
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.link_preview_options = link_preview_options
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(client, 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)
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,
link_preview_options=types.LinkPreviewOptions._parse(reply.reply_media),
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
)

View file

@ -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
)

View file

@ -321,6 +321,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>`.
@ -511,6 +514,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,
@ -550,8 +554,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
@ -1038,7 +1042,7 @@ 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)
@ -1234,6 +1238,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(