Merge branch 'Mayuri-Chan:main' into main

This commit is contained in:
Aryn 2025-06-06 20:44:14 +05:00 committed by GitHub
commit 42e9410aad
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 148 additions and 60 deletions

View file

@ -484,6 +484,7 @@ def pyrogram_api():
BusinessWeeklyOpen BusinessWeeklyOpen
BusinessWorkingHours BusinessWorkingHours
User User
Username
Chat Chat
ChatPreview ChatPreview
ChatPhoto ChatPhoto

View file

@ -18,7 +18,7 @@
# along with Pyrofork. If not, see <http://www.gnu.org/licenses/>. # along with Pyrofork. If not, see <http://www.gnu.org/licenses/>.
__fork_name__ = "PyroFork" __fork_name__ = "PyroFork"
__version__ = "2.3.63" __version__ = "2.3.64"
__license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)"
__copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>" __copyright__ = "Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>"

View file

@ -21,6 +21,7 @@ import asyncio
import inspect import inspect
import logging import logging
from collections import OrderedDict from collections import OrderedDict
from typing import Any
import pyrogram import pyrogram
from pyrogram import raw, types, utils from pyrogram import raw, types, utils
@ -337,47 +338,12 @@ class Dispatcher:
async def handler_worker(self, lock: asyncio.Lock): async def handler_worker(self, lock: asyncio.Lock):
while True: while True:
packet = await self.updates_queue.get() packet = await self.updates_queue.get()
if packet is None: if packet is None:
break break
await self._process_packet(packet, lock)
async def _process_packet(
self,
packet: tuple[raw.core.TLObject, dict[int, types.Update], dict[int, types.Update]],
lock: asyncio.Lock,
):
try: try:
update, users, chats = packet await self._handle_packet(packet, lock)
parser = self.update_parsers.get(type(update))
if parser is not None:
parsed_result = parser(update, users, chats)
if inspect.isawaitable(parsed_result):
parsed_update, handler_type = await parsed_result
else:
parsed_update, handler_type = parsed_result
else:
parsed_update, handler_type = (None, type(None))
async with lock:
for group in self.groups.values():
for handler in group:
try:
if parsed_update is not None:
if isinstance(handler, handler_type) and await handler.check(
self.client, parsed_update
):
await self._execute_callback(handler, parsed_update)
break
elif isinstance(handler, RawUpdateHandler):
await self._execute_callback(handler, update, users, chats)
break
except (pyrogram.StopPropagation, pyrogram.ContinuePropagation) as e:
if isinstance(e, pyrogram.StopPropagation):
raise
except Exception as exception:
if parsed_update is not None:
await self._handle_exception(parsed_update, exception)
except pyrogram.StopPropagation: except pyrogram.StopPropagation:
pass pass
except Exception as e: except Exception as e:
@ -385,11 +351,75 @@ class Dispatcher:
finally: finally:
self.updates_queue.task_done() self.updates_queue.task_done()
async def _handle_exception(self, parsed_update: types.Update, exception: Exception): async def _handle_packet(self, packet, lock: asyncio.Lock):
update, users, chats = packet
parser = self.update_parsers.get(type(update))
parsed_update, handler_type = (
await parser(update, users, chats)
if parser is not None else (None, type(None))
)
async with lock:
await self._dispatch_to_handlers(update, users, chats, parsed_update, handler_type)
async def _dispatch_to_handlers(
self, update, users, chats, parsed_update, handler_type,
):
for group in self.groups.values():
for handler in group:
args = await self._match_handler(
handler, update, users, chats, parsed_update, handler_type,
)
if args is None:
continue
try:
await self._execute_handler(handler, *args)
except pyrogram.StopPropagation:
raise
except pyrogram.ContinuePropagation:
continue
except Exception as error:
if parsed_update is not None:
await self._handle_exception(parsed_update, error)
break
async def _match_handler(
self, handler, update, users, chats, parsed_update, handler_type,
):
try:
if isinstance(handler, handler_type):
if await handler.check(self.client, parsed_update):
return (parsed_update,)
elif isinstance(handler, RawUpdateHandler):
if await handler.check(self.client, update):
return (update, users, chats)
except Exception as e:
log.exception(e)
return None
async def _execute_handler(self, handler, *args: Any):
if inspect.iscoroutinefunction(handler.callback):
await handler.callback(self.client, *args)
else:
await self.loop.run_in_executor(
self.client.executor,
handler.callback,
self.client,
*args
)
async def _handle_exception(
self, parsed_update: types.Update, exception: Exception,
):
handled_error = False handled_error = False
for error_handler in self.error_handlers: for error_handler in self.error_handlers:
try: try:
if await error_handler.check(self.client, parsed_update, exception): if await error_handler.check(
self.client, parsed_update, exception,
):
handled_error = True handled_error = True
break break
except pyrogram.StopPropagation: except pyrogram.StopPropagation:
@ -401,11 +431,3 @@ class Dispatcher:
if not handled_error: if not handled_error:
log.exception("Unhandled exception: %s", exception) log.exception("Unhandled exception: %s", exception)
async def _execute_callback(self, handler: Handler, *args):
if inspect.iscoroutinefunction(handler.callback):
await handler.callback(self.client, *args)
else:
await self.client.loop.run_in_executor(
self.client.executor, handler.callback, self.client, *args
)

View file

@ -890,7 +890,12 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)") command_re = re.compile(r"([\"'])(.*?)(?<!\\)\1|(\S+)")
async def func(flt, client: pyrogram.Client, message: Message): async def func(flt, client: pyrogram.Client, message: Message):
usernames = []
username = client.me.username or "" username = client.me.username or ""
if client.me.usernames:
usernames.append(username)
for user in client.me.usernames:
usernames.append(user.username)
text = message.text or message.caption text = message.text or message.caption
message.command = None message.command = None
@ -904,6 +909,24 @@ def command(commands: Union[str, List[str]], prefixes: Union[str, List[str]] = "
without_prefix = text[len(prefix):] without_prefix = text[len(prefix):]
for cmd in flt.commands: for cmd in flt.commands:
if usernames:
for username in usernames:
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
flags=re.IGNORECASE if not flt.case_sensitive else 0):
continue
without_command = re.sub(rf"{cmd}(?:@?{username})?\s?", "", without_prefix, count=1,
flags=re.IGNORECASE if not flt.case_sensitive else 0)
# match.groups are 1-indexed, group(1) is the quote, group(2) is the text
# between the quotes, group(3) is unquoted, whitespace-split text
# Remove the escape character from the arguments
message.command = [cmd] + [
re.sub(r"\\([\"'])", r"\1", m.group(2) or m.group(3) or "")
for m in command_re.finditer(without_command)
]
return True
if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix, if not re.match(rf"^(?:{cmd}(?:@?{username})?)(?:\s|$)", without_prefix,
flags=re.IGNORECASE if not flt.case_sensitive else 0): flags=re.IGNORECASE if not flt.case_sensitive else 0):
continue continue
@ -1011,12 +1034,22 @@ class user(Filter, set):
) )
async def __call__(self, _, message: Message): async def __call__(self, _, message: Message):
is_usernames_in_filters = False
if message.from_user.usernames:
for username in message.from_user.usernames:
if (
username.username in self
or username.username.lower() in self
):
is_usernames_in_filters = True
break
return (message.from_user return (message.from_user
and (message.from_user.id in self and (message.from_user.id in self
or (message.from_user.username or (message.from_user.username
and message.from_user.username.lower() in self) and message.from_user.username.lower() in self)
or ("me" in self or ("me" in self
and message.from_user.is_self))) and message.from_user.is_self))
or is_usernames_in_filters)
# noinspection PyPep8Naming # noinspection PyPep8Naming
@ -1044,6 +1077,15 @@ class chat(Filter, set):
async def __call__(self, _, message: Union[Message, Story]): async def __call__(self, _, message: Union[Message, Story]):
if isinstance(message, Story): if isinstance(message, Story):
is_usernames_in_filters = False
if message.sender_chat.usernames:
for username in message.sender_chat.usernames:
if (
username.username in self
or username.username.lower() in self
):
is_usernames_in_filters = True
break
return ( return (
message.sender_chat message.sender_chat
and ( and (
@ -1062,8 +1104,17 @@ class chat(Filter, set):
and message.from_user.username.lower() in self and message.from_user.username.lower() in self
) )
) )
) ) or is_usernames_in_filters
else: else:
is_usernames_in_filters = False
if message.chat.usernames:
for username in message._chat.usernames:
if (
username.username in self
or username.username.lower() in self
):
is_usernames_in_filters = True
break
return (message.chat return (message.chat
and (message.chat.id in self and (message.chat.id in self
or (message.chat.username or (message.chat.username
@ -1071,7 +1122,10 @@ class chat(Filter, set):
or ("me" in self or ("me" in self
and message.from_user and message.from_user
and message.from_user.is_self and message.from_user.is_self
and not message.outgoing))) and not message.outgoing))
or (is_usernames_in_filters
and not message.outgoing)
)
# noinspection PyPep8Naming # noinspection PyPep8Naming

View file

@ -808,7 +808,7 @@ class Message(Object, Update):
service_type = enums.MessageServiceType.BOT_ALLOWED service_type = enums.MessageServiceType.BOT_ALLOWED
elif isinstance(action, raw.types.MessageActionRequestedPeer) or isinstance(action, raw.types.MessageActionRequestedPeerSentMe): elif isinstance(action, raw.types.MessageActionRequestedPeer) or isinstance(action, raw.types.MessageActionRequestedPeerSentMe):
chats_shared = await types.RequestedChats._parse(client, action) chats_shared = await types.RequestedChats._parse(client, action)
service_type = enums.MessageServiceType.ChatShared service_type = enums.MessageServiceType.CHAT_SHARED
elif isinstance(action, raw.types.MessageActionTopicCreate): elif isinstance(action, raw.types.MessageActionTopicCreate):
forum_topic_created = types.ForumTopicCreated._parse(message) forum_topic_created = types.ForumTopicCreated._parse(message)
service_type = enums.MessageServiceType.FORUM_TOPIC_CREATED service_type = enums.MessageServiceType.FORUM_TOPIC_CREATED

View file

@ -77,13 +77,16 @@ class Gift(Object):
User who sent the star gift. User who sent the star gift.
owner (:obj:`~pyrogram.types.Chat`, *optional*): owner (:obj:`~pyrogram.types.Chat`, *optional*):
Current gift owner. Only available if the nfts is in telegram.
owner_name (``str``, *optional*): owner_name (``str``, *optional*):
Name of the user who received the star gift. Name of the user who received the star gift.
owner_address (``str``, *optional*): owner_address (``str``, *optional*):
Address of the gift owner in TON blockchain. Only available if the nfts is in ton network.
ton_address (``str``, *optional*):
Only available if the nfts is in ton network.
price (``int``, *optional*): price (``int``, *optional*):
Price of this gift in stars. Price of this gift in stars.
@ -163,6 +166,7 @@ class Gift(Object):
owner: Optional["types.Chat"] = None, owner: Optional["types.Chat"] = None,
owner_name: Optional[str] = None, owner_name: Optional[str] = None,
owner_address: Optional[str] = None, owner_address: Optional[str] = None,
ton_address: Optional[str] = None,
price: Optional[int] = None, price: Optional[int] = None,
convert_price: Optional[int] = None, convert_price: Optional[int] = None,
upgrade_price: Optional[int] = None, upgrade_price: Optional[int] = None,
@ -201,6 +205,7 @@ class Gift(Object):
self.owner = owner self.owner = owner
self.owner_name = owner_name self.owner_name = owner_name
self.owner_address = owner_address self.owner_address = owner_address
self.ton_address = ton_address
self.price = price self.price = price
self.convert_price = convert_price self.convert_price = convert_price
self.upgrade_price = upgrade_price self.upgrade_price = upgrade_price
@ -277,9 +282,15 @@ class Gift(Object):
) or None, ) or None,
available_amount=getattr(star_gift, "availability_issued", None), available_amount=getattr(star_gift, "availability_issued", None),
total_amount=getattr(star_gift, "availability_total", None), total_amount=getattr(star_gift, "availability_total", None),
owner=types.Chat._parse_chat(client, users.get(owner_id) or chats.get(owner_id)), owner=(
types.Chat._parse_chat(client, users.get(owner_id) or
chats.get(owner_id))
if owner_id is not None
else None
),
owner_name=getattr(star_gift, "owner_name", None), owner_name=getattr(star_gift, "owner_name", None),
owner_address=getattr(star_gift, "owner_address", None), owner_address=getattr(star_gift, "owner_address", None),
ton_address=getattr(star_gift, "gift_address", None),
is_upgraded=True, is_upgraded=True,
raw=star_gift, raw=star_gift,
client=client client=client