diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 56b2fa17..8ede4822 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -195,6 +195,7 @@ def pyrogram_api(): get_discussion_replies get_discussion_replies_count get_custom_emoji_stickers + send_web_page """, chats=""" Chats diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index b8d6dbfa..ba699c0e 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -63,6 +63,7 @@ from .send_venue import SendVenue from .send_video import SendVideo from .send_video_note import SendVideoNote from .send_voice import SendVoice +from .send_web_page import SendWebPage from .start_bot import StartBot from .stop_poll import StopPoll from .stream_media import StreamMedia @@ -93,6 +94,7 @@ class Messages( SendVideoNote, SendVoice, SendPoll, + SendWebPage, VotePoll, StartBot, StopPoll, diff --git a/pyrogram/methods/messages/send_web_page.py b/pyrogram/methods/messages/send_web_page.py new file mode 100644 index 00000000..04bbd16c --- /dev/null +++ b/pyrogram/methods/messages/send_web_page.py @@ -0,0 +1,204 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# +# 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 . + +from datetime import datetime +from typing import Union, List, Optional + +import pyrogram +from pyrogram import raw, utils, enums +from pyrogram import types + +class SendWebPage: + async def send_web_page( + self: "pyrogram.Client", + chat_id: Union[int, str], + url: str, + text: str = None, + force_large_media: bool = None, + force_small_media: bool = None, + parse_mode: Optional["enums.ParseMode"] = None, + entities: List["types.MessageEntity"] = None, + disable_notification: bool = None, + message_thread_id: int = None, + invert_media: bool = None, + reply_to_message_id: int = None, + reply_to_chat_id: Union[int, str] = None, + reply_to_story_id: int = None, + quote_text: str = None, + quote_entities: List["types.MessageEntity"] = None, + quote_offset: int = None, + schedule_date: datetime = None, + protect_content: bool = None, + reply_markup: Union[ + "types.InlineKeyboardMarkup", + "types.ReplyKeyboardMarkup", + "types.ReplyKeyboardRemove", + "types.ForceReply" + ] = None + ) -> "types.Message": + """Send text Web Page Preview. + + .. include:: /_includes/usable-by/users-bots.rst + + Parameters: + 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). + + url (``str``): + Link that will be previewed. + + text (``str``, *optional*): + Text of the message to be sent. + + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + By default, texts are parsed using both Markdown and HTML styles. + You can combine both syntaxes together. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + List of special entities that appear in message text, which can be specified instead of *parse_mode*. + + force_large_media (``bool``, *optional*): + Make web page preview image larger. + + force_small_media (``bool``, *optional*): + Make web page preview image smaller. + + invert_media (``bool``, *optional*): + Invert media. + + disable_notification (``bool``, *optional*): + Sends the message silently. + Users will receive a notification with no sound. + + message_thread_id (``int``, *optional*): + Unique identifier for the target message thread (topic) of the forum. + for forum supergroups only. + + reply_to_message_id (``int``, *optional*): + If the message is a reply, ID of the original message. + + reply_to_chat_id (``int`` | ``str``, *optional*): + If the message is a reply, ID of the original chat. + + reply_to_story_id (``int``, *optional*): + Unique identifier for the target story. + + quote_text (``str``, *optional*): + Text of the quote to be sent. + + quote_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + List of special entities that appear in quote text, which can be specified instead of *parse_mode*. + + quote_offset (``int``, *optional*): + Offset for quote in original message. + + schedule_date (:py:obj:`~datetime.datetime`, *optional*): + Date when the message will be automatically sent. + + protect_content (``bool``, *optional*): + Protects the contents of the sent message from forwarding and saving. + + reply_markup (:obj:`~pyrogram.types.InlineKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardMarkup` | :obj:`~pyrogram.types.ReplyKeyboardRemove` | :obj:`~pyrogram.types.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: + :obj:`~pyrogram.types.Message`: On success, the sent text message is returned. + + Example: + .. code-block:: python + + # Simple example + await app.send_web_page("me", "https://docs.pyrogram.org") + + # Make web preview image larger + await app.send_web_page("me", "https://docs.pyrogram.org", force_large_media=True) + + """ + + message, entities = (await utils.parse_text_entities(self, text, parse_mode, entities)).values() + + quote_text, quote_entities = (await utils.parse_text_entities(self, quote_text, parse_mode, quote_entities)).values() + + r = await self.invoke( + raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + silent=disable_notification or None, + reply_to=utils.get_reply_to( + reply_to_message_id=reply_to_message_id, + message_thread_id=message_thread_id, + reply_to_peer=await self.resolve_peer(reply_to_chat_id) if reply_to_chat_id else None, + reply_to_story_id=reply_to_story_id, + quote_text=quote_text, + quote_entities=quote_entities, + quote_offset=quote_offset, + ), + random_id=self.rnd_id(), + schedule_date=utils.datetime_to_timestamp(schedule_date), + reply_markup=await reply_markup.write(self) if reply_markup else None, + message=message, + media=raw.types.InputMediaWebPage( + url=url, + force_large_media=force_large_media, + force_small_media=force_small_media + ), + invert_media=invert_media, + entities=entities, + noforwards=protect_content + ) + ) + + if isinstance(r, raw.types.UpdateShortSentMessage): + peer = await self.resolve_peer(chat_id) + + peer_id = ( + peer.user_id + if isinstance(peer, raw.types.InputPeerUser) + else -peer.chat_id + ) + + return types.Message( + id=r.id, + chat=types.Chat( + id=peer_id, + type=enums.ChatType.PRIVATE, + client=self + ), + text=message, + date=utils.timestamp_to_datetime(r.date), + outgoing=r.out, + reply_markup=reply_markup, + entities=[ + types.MessageEntity._parse(None, entity, {}) + for entity in entities + ] if entities else None, + client=self + ) + + for i in r.updates: + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage)): + return await types.Message._parse( + self, i.message, + {i.id: i for i in r.users}, + {i.id: i for i in r.chats}, + is_scheduled=isinstance(i, raw.types.UpdateNewScheduledMessage) + )