mirror of
https://github.com/Mayuri-Chan/pyrofork.git
synced 2025-12-29 12:04:51 +00:00
Compare commits
18 commits
ecf469973e
...
8074557922
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8074557922 | ||
|
|
7562d04596 | ||
|
|
149dd4a708 | ||
|
|
4926eda4c5 | ||
|
|
c4b587b493 | ||
|
|
1108c52f53 | ||
|
|
fc84041397 | ||
|
|
71c39b8e6f | ||
|
|
bec31032cc | ||
|
|
5c9470fd4f | ||
|
|
13681302a0 | ||
|
|
c31d41e3d3 | ||
|
|
8528eea303 | ||
|
|
39cd79794e | ||
|
|
ea8ff2806f | ||
|
|
e33a9d95df | ||
|
|
ee3e9002fc | ||
|
|
4e200e2a5d |
19 changed files with 548 additions and 175 deletions
|
|
@ -435,7 +435,7 @@ updateStarsBalance#4e80a379 balance:StarsAmount = Update;
|
||||||
updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update;
|
updateBusinessBotCallbackQuery#1ea2fda7 flags:# query_id:long user_id:long connection_id:string message:Message reply_to_message:flags.2?Message chat_instance:long data:flags.0?bytes = Update;
|
||||||
updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update;
|
updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update;
|
||||||
updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update;
|
updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Update;
|
||||||
updatePaidReactionPrivacy#51ca7aec private:Bool = Update;
|
updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update;
|
||||||
|
|
||||||
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State;
|
||||||
|
|
||||||
|
|
@ -1886,7 +1886,7 @@ starsGiveawayOption#94ce852a flags:# extended:flags.0?true default:flags.1?true
|
||||||
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
|
starsGiveawayWinnersOption#54236209 flags:# default:flags.0?true users:int per_user_stars:long = StarsGiveawayWinnersOption;
|
||||||
|
|
||||||
starGift#2cc73c8 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long = StarGift;
|
starGift#2cc73c8 flags:# limited:flags.0?true sold_out:flags.1?true birthday:flags.2?true id:long sticker:Document stars:long availability_remains:flags.0?int availability_total:flags.0?int convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long = StarGift;
|
||||||
starGiftUnique#f2fe7e4a flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int = StarGift;
|
starGiftUnique#5c62d151 flags:# id:long title:string slug:string num:int owner_id:flags.0?Peer owner_name:flags.1?string owner_address:flags.2?string attributes:Vector<StarGiftAttribute> availability_issued:int availability_total:int gift_address:flags.3?string = StarGift;
|
||||||
|
|
||||||
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
|
payments.starGiftsNotModified#a388a368 = payments.StarGifts;
|
||||||
payments.starGifts#901689ea hash:int gifts:Vector<StarGift> = payments.StarGifts;
|
payments.starGifts#901689ea hash:int gifts:Vector<StarGift> = payments.StarGifts;
|
||||||
|
|
@ -1943,6 +1943,10 @@ inputSavedStarGiftChat#f101aa7f peer:InputPeer saved_id:long = InputSavedStarGif
|
||||||
|
|
||||||
payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl;
|
payments.starGiftWithdrawalUrl#84aa3a9c url:string = payments.StarGiftWithdrawalUrl;
|
||||||
|
|
||||||
|
paidReactionPrivacyDefault#206ad49e = PaidReactionPrivacy;
|
||||||
|
paidReactionPrivacyAnonymous#1f0c1ad9 = PaidReactionPrivacy;
|
||||||
|
paidReactionPrivacyPeer#dc6cfcf0 peer:InputPeer = PaidReactionPrivacy;
|
||||||
|
|
||||||
---functions---
|
---functions---
|
||||||
|
|
||||||
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X;
|
||||||
|
|
@ -1955,6 +1959,7 @@ invokeWithTakeout#aca9fd2e {X:Type} takeout_id:long query:!X = X;
|
||||||
invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X;
|
invokeWithBusinessConnection#dd289f8e {X:Type} connection_id:string query:!X = X;
|
||||||
invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X;
|
invokeWithGooglePlayIntegrity#1df92984 {X:Type} nonce:string token:string query:!X = X;
|
||||||
invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X;
|
invokeWithApnsSecret#0dae54f8 {X:Type} nonce:string secret:string query:!X = X;
|
||||||
|
invokeWithReCaptcha#adbb0f94 {X:Type} token:string query:!X = X;
|
||||||
|
|
||||||
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
auth.sendCode#a677244f phone_number:string api_id:int api_hash:string settings:CodeSettings = auth.SentCode;
|
||||||
auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
|
auth.signUp#aac7b717 flags:# no_joined_notifications:flags.0?true phone_number:string phone_code_hash:string first_name:string last_name:string = auth.Authorization;
|
||||||
|
|
@ -2340,8 +2345,8 @@ messages.editFactCheck#589ee75 peer:InputPeer msg_id:int text:TextWithEntities =
|
||||||
messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates;
|
messages.deleteFactCheck#d1da940c peer:InputPeer msg_id:int = Updates;
|
||||||
messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector<int> = Vector<FactCheck>;
|
messages.getFactCheck#b9cdc5ee peer:InputPeer msg_id:Vector<int> = Vector<FactCheck>;
|
||||||
messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult;
|
messages.requestMainWebView#c9e01e7b flags:# compact:flags.7?true fullscreen:flags.8?true peer:InputPeer bot:InputUser start_param:flags.1?string theme_params:flags.0?DataJSON platform:string = WebViewResult;
|
||||||
messages.sendPaidReaction#9dd6a67b flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?Bool = Updates;
|
messages.sendPaidReaction#58bbcb50 flags:# peer:InputPeer msg_id:int count:int random_id:long private:flags.0?PaidReactionPrivacy = Updates;
|
||||||
messages.togglePaidReactionPrivacy#849ad397 peer:InputPeer msg_id:int private:Bool = Bool;
|
messages.togglePaidReactionPrivacy#435885b5 peer:InputPeer msg_id:int private:PaidReactionPrivacy = Bool;
|
||||||
messages.getPaidReactionPrivacy#472455aa = Updates;
|
messages.getPaidReactionPrivacy#472455aa = Updates;
|
||||||
messages.viewSponsoredMessage#673ad8f1 peer:InputPeer random_id:bytes = Bool;
|
messages.viewSponsoredMessage#673ad8f1 peer:InputPeer random_id:bytes = Bool;
|
||||||
messages.clickSponsoredMessage#f093465 flags:# media:flags.0?true fullscreen:flags.1?true peer:InputPeer random_id:bytes = Bool;
|
messages.clickSponsoredMessage#f093465 flags:# media:flags.0?true fullscreen:flags.1?true peer:InputPeer random_id:bytes = Bool;
|
||||||
|
|
@ -2432,7 +2437,7 @@ channels.editLocation#58e63f6d channel:InputChannel geo_point:InputGeoPoint addr
|
||||||
channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
|
channels.toggleSlowMode#edd49ef0 channel:InputChannel seconds:int = Updates;
|
||||||
channels.getInactiveChannels#11e831ee = messages.InactiveChats;
|
channels.getInactiveChannels#11e831ee = messages.InactiveChats;
|
||||||
channels.convertToGigagroup#b290c69 channel:InputChannel = Updates;
|
channels.convertToGigagroup#b290c69 channel:InputChannel = Updates;
|
||||||
channels.getSendAs#dc770ee peer:InputPeer = channels.SendAsPeers;
|
channels.getSendAs#e785a43f flags:# for_paid_reactions:flags.0?true peer:InputPeer = channels.SendAsPeers;
|
||||||
channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory;
|
channels.deleteParticipantHistory#367544db channel:InputChannel participant:InputPeer = messages.AffectedHistory;
|
||||||
channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleJoinToSend#e4cb9580 channel:InputChannel enabled:Bool = Updates;
|
||||||
channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
|
channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates;
|
||||||
|
|
@ -2657,4 +2662,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool;
|
||||||
|
|
||||||
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo;
|
||||||
|
|
||||||
// LAYER 198
|
// LAYER 199
|
||||||
|
|
|
||||||
|
|
@ -223,6 +223,7 @@ def pyrogram_api():
|
||||||
transcribe_audio
|
transcribe_audio
|
||||||
translate_message_text
|
translate_message_text
|
||||||
start_bot
|
start_bot
|
||||||
|
delete_chat_history
|
||||||
""",
|
""",
|
||||||
chats="""
|
chats="""
|
||||||
Chats
|
Chats
|
||||||
|
|
@ -253,6 +254,7 @@ def pyrogram_api():
|
||||||
get_folders
|
get_folders
|
||||||
get_forum_topics
|
get_forum_topics
|
||||||
get_forum_topics_by_id
|
get_forum_topics_by_id
|
||||||
|
get_forum_topics_count
|
||||||
set_chat_username
|
set_chat_username
|
||||||
archive_chats
|
archive_chats
|
||||||
unarchive_chats
|
unarchive_chats
|
||||||
|
|
@ -553,6 +555,7 @@ def pyrogram_api():
|
||||||
ForumTopicCreated
|
ForumTopicCreated
|
||||||
ForumTopicEdited
|
ForumTopicEdited
|
||||||
ForumTopicClosed
|
ForumTopicClosed
|
||||||
|
ForumTopicDeleted
|
||||||
ForumTopicReopened
|
ForumTopicReopened
|
||||||
GeneralTopicHidden
|
GeneralTopicHidden
|
||||||
GeneralTopicUnhidden
|
GeneralTopicUnhidden
|
||||||
|
|
|
||||||
|
|
@ -37,68 +37,16 @@ list of the basic styles currently supported by Pyrofork.
|
||||||
- spoiler
|
- spoiler
|
||||||
- `text URL <https://pyrogram.org>`_
|
- `text URL <https://pyrogram.org>`_
|
||||||
- `user text mention <tg://user?id=123456789>`_
|
- `user text mention <tg://user?id=123456789>`_
|
||||||
|
- :emoji:`🔥`
|
||||||
- ``inline fixed-width code``
|
- ``inline fixed-width code``
|
||||||
- .. code-block:: text
|
- .. code-block:: text
|
||||||
|
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
code block
|
code block
|
||||||
|
- > Quoted text
|
||||||
|
|
||||||
Markdown Style
|
- > Quoted text with collapse/expand button
|
||||||
--------------
|
|
||||||
|
|
||||||
To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the *parse_mode* parameter when using
|
|
||||||
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
|
|
||||||
|
|
||||||
.. code-block:: text
|
|
||||||
|
|
||||||
**bold**
|
|
||||||
|
|
||||||
__italic__
|
|
||||||
|
|
||||||
--underline--
|
|
||||||
|
|
||||||
~~strike~~
|
|
||||||
|
|
||||||
||spoiler||
|
|
||||||
|
|
||||||
[text URL](https://pyrogram.org/)
|
|
||||||
|
|
||||||
[text user mention](tg://user?id=123456789)
|
|
||||||
|
|
||||||
`inline fixed-width code`
|
|
||||||
|
|
||||||
```
|
|
||||||
pre-formatted
|
|
||||||
fixed-width
|
|
||||||
code block
|
|
||||||
```
|
|
||||||
|
|
||||||
> Quoted text
|
|
||||||
|
|
||||||
**Example**:
|
|
||||||
|
|
||||||
.. code-block:: python
|
|
||||||
|
|
||||||
from pyrogram import enums
|
|
||||||
|
|
||||||
await app.send_message(
|
|
||||||
"me",
|
|
||||||
(
|
|
||||||
"**bold**, "
|
|
||||||
"__italic__, "
|
|
||||||
"--underline--, "
|
|
||||||
"~~strike~~, "
|
|
||||||
"||spoiler||, "
|
|
||||||
"[URL](https://pyrogram.org), "
|
|
||||||
"`code`, "
|
|
||||||
"```"
|
|
||||||
"for i in range(10):\n"
|
|
||||||
" print(i)"
|
|
||||||
"```"
|
|
||||||
),
|
|
||||||
parse_mode=enums.ParseMode.MARKDOWN
|
|
||||||
)
|
|
||||||
|
|
||||||
HTML Style
|
HTML Style
|
||||||
----------
|
----------
|
||||||
|
|
@ -122,10 +70,10 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<a href="tg://user?id=123456789">inline mention</a>
|
<a href="tg://user?id=123456789">inline mention</a>
|
||||||
|
|
||||||
<code>inline fixed-width code</code>
|
|
||||||
|
|
||||||
<emoji id="12345678901234567890">🔥</emoji>
|
<emoji id="12345678901234567890">🔥</emoji>
|
||||||
|
|
||||||
|
<code>inline fixed-width code</code>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
pre-formatted
|
pre-formatted
|
||||||
fixed-width
|
fixed-width
|
||||||
|
|
@ -134,6 +82,8 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<blockquote>Quoted text</blockquote>
|
<blockquote>Quoted text</blockquote>
|
||||||
|
|
||||||
|
<blockquote expandable>Quoted text with collapse/expand button</blockquote>
|
||||||
|
|
||||||
**Example**:
|
**Example**:
|
||||||
|
|
||||||
.. code-block:: python
|
.. code-block:: python
|
||||||
|
|
@ -178,6 +128,72 @@ To strictly use this mode, pass :obj:`~pyrogram.enums.HTML` to the *parse_mode*
|
||||||
|
|
||||||
<my text>
|
<my text>
|
||||||
|
|
||||||
|
Markdown Style
|
||||||
|
--------------
|
||||||
|
|
||||||
|
.. warning::
|
||||||
|
|
||||||
|
The Markdown style is not recommended for complex text formatting.
|
||||||
|
If you want to use complex text formatting such as nested entities, overlapping entities use the HTML style instead.
|
||||||
|
|
||||||
|
|
||||||
|
To strictly use this mode, pass :obj:`~pyrogram.enums.ParseMode.MARKDOWN` to the *parse_mode* parameter when using
|
||||||
|
:meth:`~pyrogram.Client.send_message`. Use the following syntax in your message:
|
||||||
|
|
||||||
|
.. code-block:: text
|
||||||
|
|
||||||
|
**bold**
|
||||||
|
|
||||||
|
__italic__
|
||||||
|
|
||||||
|
--underline--
|
||||||
|
|
||||||
|
~~strike~~
|
||||||
|
|
||||||
|
||spoiler||
|
||||||
|
|
||||||
|
[text URL](https://pyrogram.org/)
|
||||||
|
|
||||||
|
[text user mention](tg://user?id=123456789)
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
`inline fixed-width code`
|
||||||
|
|
||||||
|
```
|
||||||
|
pre-formatted
|
||||||
|
fixed-width
|
||||||
|
code block
|
||||||
|
```
|
||||||
|
|
||||||
|
> Quoted text
|
||||||
|
|
||||||
|
**> Quoted text with collapse/expand button
|
||||||
|
|
||||||
|
**Example**:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
from pyrogram import enums
|
||||||
|
|
||||||
|
await app.send_message(
|
||||||
|
"me",
|
||||||
|
(
|
||||||
|
"**bold**, "
|
||||||
|
"__italic__, "
|
||||||
|
"--underline--, "
|
||||||
|
"~~strike~~, "
|
||||||
|
"||spoiler||, "
|
||||||
|
"[URL](https://pyrogram.org), "
|
||||||
|
"`code`, "
|
||||||
|
"```"
|
||||||
|
"for i in range(10):\n"
|
||||||
|
" print(i)"
|
||||||
|
"```"
|
||||||
|
),
|
||||||
|
parse_mode=enums.ParseMode.MARKDOWN
|
||||||
|
)
|
||||||
|
|
||||||
Different Styles
|
Different Styles
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
|
@ -230,18 +246,18 @@ strike` styles, and you can still combine both Markdown and HTML together.
|
||||||
|
|
||||||
Here there are some example texts you can try sending:
|
Here there are some example texts you can try sending:
|
||||||
|
|
||||||
**Markdown**:
|
|
||||||
|
|
||||||
- ``**bold, --underline--**``
|
|
||||||
- ``**bold __italic --underline ~~strike~~--__**``
|
|
||||||
- ``**bold __and** italic__``
|
|
||||||
|
|
||||||
**HTML**:
|
**HTML**:
|
||||||
|
|
||||||
- ``<b>bold, <u>underline</u></b>``
|
- ``<b>bold, <u>underline</u></b>``
|
||||||
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
- ``<b>bold <i>italic <u>underline <s>strike</s></u></i></b>``
|
||||||
- ``<b>bold <i>and</b> italic</i>``
|
- ``<b>bold <i>and</b> italic</i>``
|
||||||
|
|
||||||
|
**Markdown (Not Recommended)**:
|
||||||
|
|
||||||
|
- ``**bold, --underline--**``
|
||||||
|
- ``**bold __italic --underline ~~strike~~--__**``
|
||||||
|
- ``**bold __and** italic__``
|
||||||
|
|
||||||
**Combined**:
|
**Combined**:
|
||||||
|
|
||||||
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
- ``--you can combine <i>HTML</i> with **Markdown**--``
|
||||||
|
|
|
||||||
|
|
@ -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.58"
|
__version__ = "2.3.59"
|
||||||
__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>"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ from .get_dialogs_count import GetDialogsCount
|
||||||
from .get_folders import GetFolders
|
from .get_folders import GetFolders
|
||||||
from .get_forum_topics import GetForumTopics
|
from .get_forum_topics import GetForumTopics
|
||||||
from .get_forum_topics_by_id import GetForumTopicsByID
|
from .get_forum_topics_by_id import GetForumTopicsByID
|
||||||
|
from .get_forum_topics_count import GetForumTopicsCount
|
||||||
from .get_send_as_chats import GetSendAsChats
|
from .get_send_as_chats import GetSendAsChats
|
||||||
from .join_chat import JoinChat
|
from .join_chat import JoinChat
|
||||||
from .leave_chat import LeaveChat
|
from .leave_chat import LeaveChat
|
||||||
|
|
@ -98,6 +99,7 @@ class Chats(
|
||||||
GetFolders,
|
GetFolders,
|
||||||
GetForumTopics,
|
GetForumTopics,
|
||||||
GetForumTopicsByID,
|
GetForumTopicsByID,
|
||||||
|
GetForumTopicsCount,
|
||||||
ArchiveChats,
|
ArchiveChats,
|
||||||
UnarchiveChats,
|
UnarchiveChats,
|
||||||
CreateGroup,
|
CreateGroup,
|
||||||
|
|
|
||||||
|
|
@ -32,7 +32,10 @@ class GetForumTopics:
|
||||||
async def get_forum_topics(
|
async def get_forum_topics(
|
||||||
self: "pyrogram.Client",
|
self: "pyrogram.Client",
|
||||||
chat_id: Union[int, str],
|
chat_id: Union[int, str],
|
||||||
limit: int = 0
|
limit: int = 0,
|
||||||
|
offset_date: int = 0,
|
||||||
|
offset_id: int = 0,
|
||||||
|
offset_topic: int = 0
|
||||||
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
||||||
"""Get one or more topic from a chat.
|
"""Get one or more topic from a chat.
|
||||||
|
|
||||||
|
|
@ -46,6 +49,15 @@ class GetForumTopics:
|
||||||
limit (``int``, *optional*):
|
limit (``int``, *optional*):
|
||||||
Limits the number of topics to be retrieved.
|
Limits the number of topics to be retrieved.
|
||||||
|
|
||||||
|
offset_date (``int``, *optional*):
|
||||||
|
Date of the last message of the last found topic.
|
||||||
|
|
||||||
|
offset_id (``int``, *optional*):
|
||||||
|
ID of the last message of the last found topic.
|
||||||
|
|
||||||
|
offset_topic (``int``, *optional*):
|
||||||
|
ID of the last found topic.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned.
|
``Generator``: On success, a generator yielding :obj:`~pyrogram.types.ForumTopic` objects is returned.
|
||||||
|
|
||||||
|
|
@ -62,7 +74,7 @@ class GetForumTopics:
|
||||||
|
|
||||||
peer = await self.resolve_peer(chat_id)
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
rpc = raw.functions.channels.GetForumTopics(channel=peer, offset_date=0, offset_id=0, offset_topic=0, limit=limit)
|
rpc = raw.functions.channels.GetForumTopics(channel=peer, offset_date=offset_date, offset_id=offset_id, offset_topic=offset_topic, limit=limit)
|
||||||
|
|
||||||
r = await self.invoke(rpc, sleep_threshold=-1)
|
r = await self.invoke(rpc, sleep_threshold=-1)
|
||||||
|
|
||||||
|
|
|
||||||
63
pyrogram/methods/chats/get_forum_topics_count.py
Normal file
63
pyrogram/methods/chats/get_forum_topics_count.py
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Pyrofork - 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 Pyrofork.
|
||||||
|
#
|
||||||
|
# Pyrofork 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.
|
||||||
|
#
|
||||||
|
# Pyrofork 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 Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
import logging
|
||||||
|
from typing import Union, Optional, AsyncGenerator
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw
|
||||||
|
from pyrogram import types
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class GetForumTopicsCount:
|
||||||
|
async def get_forum_topics_count(
|
||||||
|
self: "pyrogram.Client",
|
||||||
|
chat_id: Union[int, str]
|
||||||
|
) -> Optional[AsyncGenerator["types.ForumTopic", None]]:
|
||||||
|
"""Get forum topics count from a chat.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
You can also use chat public link in form of *t.me/<username>* (str).
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
``int``: On success, the count of forum topics is returned.
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# get all forum topics count
|
||||||
|
app.get_forum_topics_count(chat_id)
|
||||||
|
|
||||||
|
Raises:
|
||||||
|
ValueError: In case of invalid arguments.
|
||||||
|
"""
|
||||||
|
|
||||||
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
rpc = raw.functions.channels.GetForumTopics(channel=peer, offset_date=0, offset_id=0, offset_topic=0, limit=0)
|
||||||
|
|
||||||
|
r = await self.invoke(rpc, sleep_threshold=-1)
|
||||||
|
|
||||||
|
return r.count
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
from .copy_media_group import CopyMediaGroup
|
from .copy_media_group import CopyMediaGroup
|
||||||
from .copy_message import CopyMessage
|
from .copy_message import CopyMessage
|
||||||
|
from .delete_chat_history import DeleteChatHistory
|
||||||
from .delete_messages import DeleteMessages
|
from .delete_messages import DeleteMessages
|
||||||
from .delete_scheduled_messages import DeleteScheduledMessages
|
from .delete_scheduled_messages import DeleteScheduledMessages
|
||||||
from .download_media import DownloadMedia
|
from .download_media import DownloadMedia
|
||||||
|
|
@ -78,6 +79,7 @@ from .transcribe_audio import TranscribeAudio
|
||||||
from .translate_text import TranslateText
|
from .translate_text import TranslateText
|
||||||
|
|
||||||
class Messages(
|
class Messages(
|
||||||
|
DeleteChatHistory,
|
||||||
DeleteMessages,
|
DeleteMessages,
|
||||||
DeleteScheduledMessages,
|
DeleteScheduledMessages,
|
||||||
EditMessageCaption,
|
EditMessageCaption,
|
||||||
|
|
|
||||||
102
pyrogram/methods/messages/delete_chat_history.py
Normal file
102
pyrogram/methods/messages/delete_chat_history.py
Normal file
|
|
@ -0,0 +1,102 @@
|
||||||
|
# Pyrofork - 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 Pyrofork.
|
||||||
|
#
|
||||||
|
# Pyrofork 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.
|
||||||
|
#
|
||||||
|
# Pyrofork 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 Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from datetime import datetime
|
||||||
|
import logging
|
||||||
|
from typing import Union
|
||||||
|
|
||||||
|
import pyrogram
|
||||||
|
from pyrogram import raw
|
||||||
|
from pyrogram import utils
|
||||||
|
|
||||||
|
log = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class DeleteChatHistory:
|
||||||
|
async def delete_chat_history(
|
||||||
|
self: "pyrogram.Client",
|
||||||
|
chat_id: Union[int, str],
|
||||||
|
max_id: int = 0,
|
||||||
|
revoke: bool = None,
|
||||||
|
just_clear = None,
|
||||||
|
min_date: datetime = None,
|
||||||
|
max_date: datetime = None,
|
||||||
|
) -> int:
|
||||||
|
"""Delete the history of a chat.
|
||||||
|
|
||||||
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
chat_id (``int`` | ``str``):
|
||||||
|
Unique identifier (int) or username (str) of the target chat.
|
||||||
|
|
||||||
|
max_id (``int``, *optional*):
|
||||||
|
Maximum ID of message to delete.
|
||||||
|
|
||||||
|
revoke (``bool``, *optional*):
|
||||||
|
Deletes messages history for everyone.
|
||||||
|
Required ``True`` if using in channel.
|
||||||
|
|
||||||
|
just_clear (``bool``, *optional*):
|
||||||
|
If True, clear history for the current user, without actually removing chat.
|
||||||
|
For private and simple group chats only.
|
||||||
|
|
||||||
|
min_date (:py:obj:`~datetime.datetime`, *optional*):
|
||||||
|
Delete all messages newer than this time.
|
||||||
|
For private and simple group chats only.
|
||||||
|
|
||||||
|
max_date (:py:obj:`~datetime.datetime`, *optional*):
|
||||||
|
Delete all messages older than this time.
|
||||||
|
For private and simple group chats only.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
``int``: Amount of affected messages
|
||||||
|
|
||||||
|
Example:
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
# Delete all messages in channel
|
||||||
|
await app.delete_chat_history(chat_id, revoke=True)
|
||||||
|
"""
|
||||||
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
|
if isinstance(peer, raw.types.InputPeerChannel):
|
||||||
|
r = await self.invoke(
|
||||||
|
raw.functions.channels.DeleteHistory(
|
||||||
|
channel=raw.types.InputChannel(
|
||||||
|
channel_id=peer.channel_id,
|
||||||
|
access_hash=peer.access_hash
|
||||||
|
),
|
||||||
|
max_id=max_id,
|
||||||
|
for_everyone=revoke
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
r = await self.invoke(
|
||||||
|
raw.functions.messages.DeleteHistory(
|
||||||
|
peer=peer,
|
||||||
|
max_id=max_id,
|
||||||
|
just_clear=just_clear,
|
||||||
|
revoke=revoke,
|
||||||
|
min_date=utils.datetime_to_timestamp(min_date),
|
||||||
|
max_date=utils.datetime_to_timestamp(max_date)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
return len(r.updates[0].messages) if isinstance(peer, raw.types.InputPeerChannel) else r.pts_count
|
||||||
|
|
@ -23,10 +23,7 @@ from datetime import datetime
|
||||||
from typing import Union, BinaryIO, List, Optional, Callable
|
from typing import Union, BinaryIO, List, Optional, Callable
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import StopTransmission, enums
|
from pyrogram import StopTransmission, enums, raw, types, utils
|
||||||
from pyrogram import raw
|
|
||||||
from pyrogram import types
|
|
||||||
from pyrogram import utils
|
|
||||||
from pyrogram.errors import FilePartMissing
|
from pyrogram.errors import FilePartMissing
|
||||||
from pyrogram.file_id import FileType
|
from pyrogram.file_id import FileType
|
||||||
|
|
||||||
|
|
@ -55,7 +52,7 @@ class SendVideo:
|
||||||
reply_to_chat_id: Union[int, str] = None,
|
reply_to_chat_id: Union[int, str] = None,
|
||||||
quote_text: str = None,
|
quote_text: str = None,
|
||||||
quote_entities: List["types.MessageEntity"] = None,
|
quote_entities: List["types.MessageEntity"] = None,
|
||||||
cover: Optional[Union[str, "io.BytesIO"]] = None,
|
cover: Union[str, BinaryIO] = None,
|
||||||
start_timestamp: int = None,
|
start_timestamp: int = None,
|
||||||
schedule_date: datetime = None,
|
schedule_date: datetime = None,
|
||||||
protect_content: bool = None,
|
protect_content: bool = None,
|
||||||
|
|
@ -161,8 +158,12 @@ class SendVideo:
|
||||||
List of special entities that appear in quote_text, which can be specified instead of *parse_mode*.
|
List of special entities that appear in quote_text, which can be specified instead of *parse_mode*.
|
||||||
for reply_to_message only.
|
for reply_to_message only.
|
||||||
|
|
||||||
cover (``str`` | :obj:`io.BytesIO`, *optional*):
|
cover (``str`` | ``BinaryIO``, *optional*):
|
||||||
Cover of the video; pass None to skip cover uploading.
|
Video cover.
|
||||||
|
Pass a file_id as string to attach a photo that exists on the Telegram servers,
|
||||||
|
pass a HTTP URL as a string for Telegram to get a video from the Internet,
|
||||||
|
pass a file path as string to upload a new photo civer that exists on your local machine, or
|
||||||
|
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
|
||||||
|
|
||||||
start_timestamp (``int``, *optional*):
|
start_timestamp (``int``, *optional*):
|
||||||
Timestamp from which the video playing must start, in seconds.
|
Timestamp from which the video playing must start, in seconds.
|
||||||
|
|
@ -224,6 +225,9 @@ class SendVideo:
|
||||||
# Send self-destructing video
|
# Send self-destructing video
|
||||||
await app.send_video("me", "video.mp4", ttl_seconds=10)
|
await app.send_video("me", "video.mp4", ttl_seconds=10)
|
||||||
|
|
||||||
|
# Add video_cover to the video
|
||||||
|
await app.send_video(channel_id, "video.mp4", video_cover="coverku.jpg")
|
||||||
|
|
||||||
# Keep track of the progress while uploading
|
# Keep track of the progress while uploading
|
||||||
async def progress(current, total):
|
async def progress(current, total):
|
||||||
print(f"{current * 100 / total:.1f}%")
|
print(f"{current * 100 / total:.1f}%")
|
||||||
|
|
@ -231,6 +235,9 @@ class SendVideo:
|
||||||
await app.send_video("me", "video.mp4", progress=progress)
|
await app.send_video("me", "video.mp4", progress=progress)
|
||||||
"""
|
"""
|
||||||
file = None
|
file = None
|
||||||
|
vidcover_file = None
|
||||||
|
vidcover_media = None
|
||||||
|
peer = await self.resolve_peer(chat_id)
|
||||||
|
|
||||||
reply_to = await utils.get_reply_to(
|
reply_to = await utils.get_reply_to(
|
||||||
client=self,
|
client=self,
|
||||||
|
|
@ -245,6 +252,45 @@ class SendVideo:
|
||||||
)
|
)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
if cover is not None:
|
||||||
|
if isinstance(cover, str):
|
||||||
|
if os.path.isfile(cover):
|
||||||
|
vidcover_media = await self.invoke(
|
||||||
|
raw.functions.messages.UploadMedia(
|
||||||
|
peer=peer,
|
||||||
|
media=raw.types.InputMediaUploadedPhoto(
|
||||||
|
file=await self.save_file(cover)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
elif re.match("^https?://", cover):
|
||||||
|
vidcover_media = await self.invoke(
|
||||||
|
raw.functions.messages.UploadMedia(
|
||||||
|
peer=peer,
|
||||||
|
media=raw.types.InputMediaPhotoExternal(
|
||||||
|
url=cover
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
vidcover_file = utils.get_input_media_from_file_id(cover, FileType.PHOTO).id
|
||||||
|
else:
|
||||||
|
vidcover_media = await self.invoke(
|
||||||
|
raw.functions.messages.UploadMedia(
|
||||||
|
peer=peer,
|
||||||
|
media=raw.types.InputMediaUploadedPhoto(
|
||||||
|
file=await self.save_file(cover)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if vidcover_media:
|
||||||
|
vidcover_file = raw.types.InputPhoto(
|
||||||
|
id=vidcover_media.photo.id,
|
||||||
|
access_hash=vidcover_media.photo.access_hash,
|
||||||
|
file_reference=vidcover_media.photo.file_reference
|
||||||
|
)
|
||||||
|
|
||||||
if isinstance(video, str):
|
if isinstance(video, str):
|
||||||
if os.path.isfile(video):
|
if os.path.isfile(video):
|
||||||
thumb = await self.save_file(thumb)
|
thumb = await self.save_file(thumb)
|
||||||
|
|
@ -264,7 +310,7 @@ class SendVideo:
|
||||||
),
|
),
|
||||||
raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video))
|
raw.types.DocumentAttributeFilename(file_name=file_name or os.path.basename(video))
|
||||||
],
|
],
|
||||||
video_cover=await self.save_file(cover) if cover else None,
|
video_cover=vidcover_file,
|
||||||
video_timestamp=start_timestamp
|
video_timestamp=start_timestamp
|
||||||
)
|
)
|
||||||
elif re.match("^https?://", video):
|
elif re.match("^https?://", video):
|
||||||
|
|
@ -272,7 +318,7 @@ class SendVideo:
|
||||||
url=video,
|
url=video,
|
||||||
ttl_seconds=ttl_seconds,
|
ttl_seconds=ttl_seconds,
|
||||||
spoiler=has_spoiler,
|
spoiler=has_spoiler,
|
||||||
video_cover=await self.save_file(cover) if cover else None,
|
video_cover=vidcover_file,
|
||||||
video_timestamp=start_timestamp
|
video_timestamp=start_timestamp
|
||||||
)
|
)
|
||||||
else:
|
else:
|
||||||
|
|
@ -296,14 +342,14 @@ class SendVideo:
|
||||||
),
|
),
|
||||||
raw.types.DocumentAttributeFilename(file_name=file_name or video.name)
|
raw.types.DocumentAttributeFilename(file_name=file_name or video.name)
|
||||||
],
|
],
|
||||||
video_cover=await self.save_file(cover) if cover else None,
|
video_cover=vidcover_file,
|
||||||
video_timestamp=start_timestamp
|
video_timestamp=start_timestamp
|
||||||
)
|
)
|
||||||
|
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
rpc = raw.functions.messages.SendMedia(
|
rpc = raw.functions.messages.SendMedia(
|
||||||
peer=await self.resolve_peer(chat_id),
|
peer=peer,
|
||||||
media=media,
|
media=media,
|
||||||
silent=disable_notification or None,
|
silent=disable_notification or None,
|
||||||
reply_to=reply_to,
|
reply_to=reply_to,
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class GetChatGifts:
|
||||||
limit: int = 0,
|
limit: int = 0,
|
||||||
offset: str = ""
|
offset: str = ""
|
||||||
):
|
):
|
||||||
"""Get user star gifts.
|
"""Get all gifts owned by specified chat.
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ class GetChatGiftsCount:
|
||||||
exclude_limited: Optional[bool] = None,
|
exclude_limited: Optional[bool] = None,
|
||||||
exclude_upgraded: Optional[bool] = None
|
exclude_upgraded: Optional[bool] = None
|
||||||
) -> int:
|
) -> int:
|
||||||
"""Get the total count of star gifts of specified user.
|
"""Get the total count of owned gifts of specified chat.
|
||||||
|
|
||||||
.. include:: /_includes/usable-by/users.rst
|
.. include:: /_includes/usable-by/users.rst
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -37,7 +37,7 @@ PRE_DELIM = "```"
|
||||||
BLOCKQUOTE_DELIM = ">"
|
BLOCKQUOTE_DELIM = ">"
|
||||||
BLOCKQUOTE_EXPANDABLE_DELIM = "**>"
|
BLOCKQUOTE_EXPANDABLE_DELIM = "**>"
|
||||||
|
|
||||||
MARKDOWN_RE = re.compile(r"({d})|(!?)\[(.+?)\]\((.+?)\)".format(
|
MARKDOWN_RE = re.compile(r"({d})".format(
|
||||||
d="|".join(
|
d="|".join(
|
||||||
["".join(i) for i in [
|
["".join(i) for i in [
|
||||||
[rf"\{j}" for j in i]
|
[rf"\{j}" for j in i]
|
||||||
|
|
@ -52,6 +52,7 @@ MARKDOWN_RE = re.compile(r"({d})|(!?)\[(.+?)\]\((.+?)\)".format(
|
||||||
]
|
]
|
||||||
]]
|
]]
|
||||||
)))
|
)))
|
||||||
|
URL_RE = re.compile(r"(!?)\[(.+?)\]\((.+?)\)")
|
||||||
|
|
||||||
OPENING_TAG = "<{}>"
|
OPENING_TAG = "<{}>"
|
||||||
CLOSING_TAG = "</{}>"
|
CLOSING_TAG = "</{}>"
|
||||||
|
|
@ -118,7 +119,7 @@ class Markdown:
|
||||||
|
|
||||||
for i, match in enumerate(re.finditer(MARKDOWN_RE, text)):
|
for i, match in enumerate(re.finditer(MARKDOWN_RE, text)):
|
||||||
start, _ = match.span()
|
start, _ = match.span()
|
||||||
delim, is_emoji, text_url, url = match.groups()
|
delim = match.group(1)
|
||||||
full = match.group(0)
|
full = match.group(0)
|
||||||
|
|
||||||
if delim in FIXED_WIDTH_DELIMS:
|
if delim in FIXED_WIDTH_DELIMS:
|
||||||
|
|
@ -127,16 +128,6 @@ class Markdown:
|
||||||
if is_fixed_width and delim not in FIXED_WIDTH_DELIMS:
|
if is_fixed_width and delim not in FIXED_WIDTH_DELIMS:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
if not is_emoji and text_url:
|
|
||||||
text = utils.replace_once(text, full, URL_MARKUP.format(url, text_url), start)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if is_emoji:
|
|
||||||
emoji = text_url
|
|
||||||
emoji_id = url.lstrip("tg://emoji?id=")
|
|
||||||
text = utils.replace_once(text, full, EMOJI_MARKUP.format(emoji_id, emoji), start)
|
|
||||||
continue
|
|
||||||
|
|
||||||
if delim == BOLD_DELIM:
|
if delim == BOLD_DELIM:
|
||||||
tag = "b"
|
tag = "b"
|
||||||
elif delim == ITALIC_DELIM:
|
elif delim == ITALIC_DELIM:
|
||||||
|
|
@ -169,6 +160,21 @@ class Markdown:
|
||||||
|
|
||||||
text = utils.replace_once(text, delim, tag, start)
|
text = utils.replace_once(text, delim, tag, start)
|
||||||
|
|
||||||
|
for i, match in enumerate(re.finditer(URL_RE, text)):
|
||||||
|
start, _ = match.span()
|
||||||
|
is_emoji, text_url, url = match.groups()
|
||||||
|
full = match.group(0)
|
||||||
|
|
||||||
|
if not is_emoji and text_url:
|
||||||
|
text = utils.replace_once(text, full, URL_MARKUP.format(url, text_url), start)
|
||||||
|
continue
|
||||||
|
|
||||||
|
if is_emoji:
|
||||||
|
emoji = text_url
|
||||||
|
emoji_id = url.lstrip("tg://emoji?id=")
|
||||||
|
text = utils.replace_once(text, full, EMOJI_MARKUP.format(emoji_id, emoji), start)
|
||||||
|
continue
|
||||||
|
|
||||||
for placeholder, code_section in placeholders.items():
|
for placeholder, code_section in placeholders.items():
|
||||||
text = text.replace(placeholder, code_section)
|
text = text.replace(placeholder, code_section)
|
||||||
|
|
||||||
|
|
@ -176,78 +182,110 @@ class Markdown:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def unparse(text: str, entities: list):
|
def unparse(text: str, entities: list):
|
||||||
|
"""
|
||||||
|
Performs the reverse operation to .parse(), effectively returning
|
||||||
|
markdown-like syntax given a normal text and its MessageEntity's.
|
||||||
|
|
||||||
|
:param text: the text to be reconverted into markdown.
|
||||||
|
:param entities: list of MessageEntity's applied to the text.
|
||||||
|
:return: a markdown-like text representing the combination of both inputs.
|
||||||
|
"""
|
||||||
|
delimiters = {
|
||||||
|
MessageEntityType.BOLD: BOLD_DELIM,
|
||||||
|
MessageEntityType.ITALIC: ITALIC_DELIM,
|
||||||
|
MessageEntityType.UNDERLINE: UNDERLINE_DELIM,
|
||||||
|
MessageEntityType.STRIKETHROUGH: STRIKE_DELIM,
|
||||||
|
MessageEntityType.CODE: CODE_DELIM,
|
||||||
|
MessageEntityType.PRE: PRE_DELIM,
|
||||||
|
MessageEntityType.BLOCKQUOTE: BLOCKQUOTE_DELIM,
|
||||||
|
MessageEntityType.EXPANDABLE_BLOCKQUOTE: BLOCKQUOTE_EXPANDABLE_DELIM,
|
||||||
|
MessageEntityType.SPOILER: SPOILER_DELIM
|
||||||
|
}
|
||||||
|
|
||||||
text = utils.add_surrogates(text)
|
text = utils.add_surrogates(text)
|
||||||
|
|
||||||
entities_offsets = []
|
insert_at = []
|
||||||
|
for i, entity in enumerate(entities):
|
||||||
for entity in entities:
|
s = entity.offset
|
||||||
entity_type = entity.type
|
e = entity.offset + entity.length
|
||||||
start = entity.offset
|
delimiter = delimiters.get(entity.type, None)
|
||||||
end = start + entity.length
|
if delimiter:
|
||||||
|
if entity.type == MessageEntityType.PRE:
|
||||||
if entity_type == MessageEntityType.BOLD:
|
inside_blockquote = any(
|
||||||
start_tag = end_tag = BOLD_DELIM
|
blk_entity.offset <= s < blk_entity.offset + blk_entity.length and
|
||||||
elif entity_type == MessageEntityType.ITALIC:
|
blk_entity.offset < e <= blk_entity.offset + blk_entity.length
|
||||||
start_tag = end_tag = ITALIC_DELIM
|
for blk_entity in entities
|
||||||
elif entity_type == MessageEntityType.UNDERLINE:
|
if blk_entity.type == MessageEntityType.BLOCKQUOTE
|
||||||
start_tag = end_tag = UNDERLINE_DELIM
|
)
|
||||||
elif entity_type == MessageEntityType.STRIKETHROUGH:
|
is_expandable = any(
|
||||||
start_tag = end_tag = STRIKE_DELIM
|
blk_entity.offset <= s < blk_entity.offset + blk_entity.length and
|
||||||
elif entity_type == MessageEntityType.CODE:
|
blk_entity.offset < e <= blk_entity.offset + blk_entity.length and
|
||||||
start_tag = end_tag = CODE_DELIM
|
blk_entity.collapsed
|
||||||
elif entity_type == MessageEntityType.PRE:
|
for blk_entity in entities
|
||||||
language = getattr(entity, "language", "") or ""
|
if blk_entity.type == MessageEntityType.BLOCKQUOTE
|
||||||
start_tag = f"{PRE_DELIM}{language}\n"
|
)
|
||||||
end_tag = f"\n{PRE_DELIM}"
|
if inside_blockquote:
|
||||||
elif entity_type == MessageEntityType.BLOCKQUOTE:
|
if is_expandable:
|
||||||
if entity.collapsed:
|
if entity.language:
|
||||||
start_tag = BLOCKQUOTE_EXPANDABLE_DELIM + " "
|
open_delimiter = f"{delimiter}{entity.language}\n**>"
|
||||||
|
else:
|
||||||
|
open_delimiter = f"{delimiter}\n**>"
|
||||||
|
close_delimiter = f"\n**>{delimiter}"
|
||||||
|
else:
|
||||||
|
if entity.language:
|
||||||
|
open_delimiter = f"{delimiter}{entity.language}\n>"
|
||||||
|
else:
|
||||||
|
open_delimiter = f"{delimiter}\n>"
|
||||||
|
close_delimiter = f"\n>{delimiter}"
|
||||||
|
else:
|
||||||
|
open_delimiter = delimiter
|
||||||
|
close_delimiter = delimiter
|
||||||
|
insert_at.append((s, i, open_delimiter))
|
||||||
|
insert_at.append((e, -i, close_delimiter))
|
||||||
|
elif entity.type != MessageEntityType.BLOCKQUOTE and entity.type != MessageEntityType.EXPANDABLE_BLOCKQUOTE:
|
||||||
|
open_delimiter = delimiter
|
||||||
|
close_delimiter = delimiter
|
||||||
|
insert_at.append((s, i, open_delimiter))
|
||||||
|
insert_at.append((e, -i, close_delimiter))
|
||||||
else:
|
else:
|
||||||
start_tag = BLOCKQUOTE_DELIM + " "
|
# Handle multiline blockquotes
|
||||||
end_tag = ""
|
text_subset = text[s:e]
|
||||||
blockquote_text = text[start:end]
|
lines = text_subset.splitlines()
|
||||||
lines = blockquote_text.split("\n")
|
for line_num, line in enumerate(lines):
|
||||||
last_length = 0
|
line_start = s + sum(len(l) + 1 for l in lines[:line_num])
|
||||||
for line in lines:
|
if entity.collapsed:
|
||||||
if len(line) == 0 and last_length == end:
|
insert_at.append((line_start, i, BLOCKQUOTE_EXPANDABLE_DELIM))
|
||||||
continue
|
else:
|
||||||
start_offset = start+last_length
|
insert_at.append((line_start, i, BLOCKQUOTE_DELIM))
|
||||||
last_length = last_length+len(line)
|
# No closing delimiter for blockquotes
|
||||||
end_offset = start_offset+last_length
|
|
||||||
entities_offsets.append((start_tag, start_offset,))
|
|
||||||
entities_offsets.append((end_tag, end_offset,))
|
|
||||||
last_length = last_length+1
|
|
||||||
continue
|
|
||||||
elif entity_type == MessageEntityType.SPOILER:
|
|
||||||
start_tag = end_tag = SPOILER_DELIM
|
|
||||||
elif entity_type == MessageEntityType.TEXT_LINK:
|
|
||||||
url = entity.url
|
|
||||||
start_tag = "["
|
|
||||||
end_tag = f"]({url})"
|
|
||||||
elif entity_type == MessageEntityType.TEXT_MENTION:
|
|
||||||
user = entity.user
|
|
||||||
start_tag = "["
|
|
||||||
end_tag = f"](tg://user?id={user.id})"
|
|
||||||
elif entity_type == MessageEntityType.CUSTOM_EMOJI:
|
|
||||||
emoji_id = entity.custom_emoji_id
|
|
||||||
start_tag = ""
|
|
||||||
else:
|
else:
|
||||||
continue
|
url = None
|
||||||
|
is_emoji = False
|
||||||
|
if entity.type == MessageEntityType.TEXT_LINK:
|
||||||
|
url = entity.url
|
||||||
|
elif entity.type == MessageEntityType.TEXT_MENTION:
|
||||||
|
url = f'tg://user?id={entity.user.id}'
|
||||||
|
elif entity.type == MessageEntityType.CUSTOM_EMOJI:
|
||||||
|
url = f"tg://emoji?id={entity.custom_emoji_id}"
|
||||||
|
is_emoji = True
|
||||||
|
if url:
|
||||||
|
if is_emoji:
|
||||||
|
insert_at.append((s, i, ''))
|
||||||
|
|
||||||
entities_offsets.append((start_tag, start,))
|
insert_at.sort(key=lambda t: (t[0], t[1]))
|
||||||
entities_offsets.append((end_tag, end,))
|
while insert_at:
|
||||||
|
at, _, what = insert_at.pop()
|
||||||
|
|
||||||
entities_offsets = map(
|
# If we are in the middle of a surrogate nudge the position by -1.
|
||||||
lambda x: x[1],
|
# Otherwise we would end up with malformed text and fail to encode.
|
||||||
sorted(
|
# For example of bad input: "Hi \ud83d\ude1c"
|
||||||
enumerate(entities_offsets),
|
# https://en.wikipedia.org/wiki/UTF-16#U+010000_to_U+10FFFF
|
||||||
key=lambda x: (x[1][1], x[0]),
|
while utils.within_surrogate(text, at):
|
||||||
reverse=True
|
at += 1
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
for entity, offset in entities_offsets:
|
text = text[:at] + what + text[at:]
|
||||||
text = text[:offset] + entity + text[offset:]
|
|
||||||
|
|
||||||
return utils.remove_surrogates(text)
|
return utils.remove_surrogates(text)
|
||||||
|
|
|
||||||
|
|
@ -40,3 +40,16 @@ def remove_surrogates(text):
|
||||||
|
|
||||||
def replace_once(source: str, old: str, new: str, start: int):
|
def replace_once(source: str, old: str, new: str, start: int):
|
||||||
return source[:start] + source[start:].replace(old, new, 1)
|
return source[:start] + source[start:].replace(old, new, 1)
|
||||||
|
|
||||||
|
def within_surrogate(text, index, *, length=None):
|
||||||
|
"""
|
||||||
|
`True` if ``index`` is within a surrogate (before and after it, not at!).
|
||||||
|
"""
|
||||||
|
if length is None:
|
||||||
|
length = len(text)
|
||||||
|
|
||||||
|
return (
|
||||||
|
1 < index < len(text) and # in bounds
|
||||||
|
'\ud800' <= text[index - 1] <= '\udbff' and # previous is
|
||||||
|
'\ud800' <= text[index] <= '\udfff' # current is
|
||||||
|
)
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,7 @@ from functools import partial
|
||||||
from typing import List, Match, Union, BinaryIO, Optional, Callable
|
from typing import List, Match, Union, BinaryIO, Optional, Callable
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw, enums
|
from pyrogram import enums, raw, types, utils
|
||||||
from pyrogram import types
|
|
||||||
from pyrogram import utils
|
|
||||||
from pyrogram.errors import ChannelPrivate, MessageIdsEmpty, PeerIdInvalid
|
from pyrogram.errors import ChannelPrivate, MessageIdsEmpty, PeerIdInvalid
|
||||||
from pyrogram.parser import utils as parser_utils, Parser
|
from pyrogram.parser import utils as parser_utils, Parser
|
||||||
from ..object import Object
|
from ..object import Object
|
||||||
|
|
@ -424,6 +422,9 @@ class Message(Object, Update):
|
||||||
link (``str``, *property*):
|
link (``str``, *property*):
|
||||||
Generate a link to this message, only for groups and channels.
|
Generate a link to this message, only for groups and channels.
|
||||||
|
|
||||||
|
content (``str``, *property*):
|
||||||
|
The text or caption content of the message.
|
||||||
|
|
||||||
scheduled (``bool``, *optional*):
|
scheduled (``bool``, *optional*):
|
||||||
Message is a scheduled message and still in schedule.
|
Message is a scheduled message and still in schedule.
|
||||||
|
|
||||||
|
|
@ -1112,7 +1113,7 @@ class Message(Object, Update):
|
||||||
video_note = types.VideoNote._parse(client, doc, video_attributes)
|
video_note = types.VideoNote._parse(client, doc, video_attributes)
|
||||||
media_type = enums.MessageMediaType.VIDEO_NOTE
|
media_type = enums.MessageMediaType.VIDEO_NOTE
|
||||||
else:
|
else:
|
||||||
video = types.Video._parse(client, doc, video_attributes, file_name, media.ttl_seconds)
|
video = types.Video._parse(client, doc, video_attributes, file_name, media.ttl_seconds, media.video_cover, media.video_timestamp)
|
||||||
media_type = enums.MessageMediaType.VIDEO
|
media_type = enums.MessageMediaType.VIDEO
|
||||||
has_media_spoiler = media.spoiler
|
has_media_spoiler = media.spoiler
|
||||||
|
|
||||||
|
|
@ -1358,6 +1359,10 @@ class Message(Object, Update):
|
||||||
else:
|
else:
|
||||||
return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.id}"
|
return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.id}"
|
||||||
|
|
||||||
|
@property
|
||||||
|
def content(self) -> str:
|
||||||
|
return self.text or self.caption or Str("").init([])
|
||||||
|
|
||||||
async def get_media_group(self) -> List["types.Message"]:
|
async def get_media_group(self) -> List["types.Message"]:
|
||||||
"""Bound method *get_media_group* of :obj:`~pyrogram.types.Message`.
|
"""Bound method *get_media_group* of :obj:`~pyrogram.types.Message`.
|
||||||
|
|
||||||
|
|
@ -3593,7 +3598,7 @@ class Message(Object, Update):
|
||||||
quote_entities: List["types.MessageEntity"] = None,
|
quote_entities: List["types.MessageEntity"] = None,
|
||||||
allow_paid_broadcast: bool = None,
|
allow_paid_broadcast: bool = None,
|
||||||
message_effect_id: int = None,
|
message_effect_id: int = None,
|
||||||
cover: Optional[Union[str, "io.BytesIO"]] = None,
|
cover: Union[str, BinaryIO] = None,
|
||||||
start_timestamp: int = None,
|
start_timestamp: int = None,
|
||||||
schedule_date: datetime = None,
|
schedule_date: datetime = None,
|
||||||
invert_media: bool = None,
|
invert_media: bool = None,
|
||||||
|
|
@ -3700,8 +3705,12 @@ class Message(Object, Update):
|
||||||
allow_paid_broadcast (``bool``, *optional*):
|
allow_paid_broadcast (``bool``, *optional*):
|
||||||
Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots.
|
Pass True to allow the message to ignore regular broadcast limits for a small fee; for bots.
|
||||||
|
|
||||||
cover (``str`` | :obj:`io.BytesIO`, *optional*):
|
cover (``str`` | ``BinaryIO``, *optional*):
|
||||||
Cover of the video; pass None to skip cover uploading.
|
Video cover.
|
||||||
|
Pass a file_id as string to attach a photo that exists on the Telegram servers,
|
||||||
|
pass a HTTP URL as a string for Telegram to get a video from the Internet,
|
||||||
|
pass a file path as string to upload a new photo civer that exists on your local machine, or
|
||||||
|
pass a binary file-like object with its attribute ".name" set for in-memory uploads.
|
||||||
|
|
||||||
start_timestamp (``int``, *optional*):
|
start_timestamp (``int``, *optional*):
|
||||||
Timestamp from which the video playing must start, in seconds.
|
Timestamp from which the video playing must start, in seconds.
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,7 @@ from datetime import datetime
|
||||||
from typing import List
|
from typing import List
|
||||||
|
|
||||||
import pyrogram
|
import pyrogram
|
||||||
from pyrogram import raw, utils
|
from pyrogram import raw, types, utils
|
||||||
from pyrogram import types
|
|
||||||
from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource
|
from pyrogram.file_id import FileId, FileType, FileUniqueId, FileUniqueType, ThumbnailSource
|
||||||
from ..object import Object
|
from ..object import Object
|
||||||
|
|
||||||
|
|
@ -67,6 +66,12 @@ class Video(Object):
|
||||||
|
|
||||||
thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*):
|
thumbs (List of :obj:`~pyrogram.types.Thumbnail`, *optional*):
|
||||||
Video thumbnails.
|
Video thumbnails.
|
||||||
|
|
||||||
|
cover (:obj:`~pyrogram.types.Photo`, *optional*):
|
||||||
|
Video cover.
|
||||||
|
|
||||||
|
start_timestamp (``int``, *optional*):
|
||||||
|
Video startpoint, in seconds.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
|
|
@ -84,7 +89,9 @@ class Video(Object):
|
||||||
supports_streaming: bool = None,
|
supports_streaming: bool = None,
|
||||||
ttl_seconds: int = None,
|
ttl_seconds: int = None,
|
||||||
date: datetime = None,
|
date: datetime = None,
|
||||||
thumbs: List["types.Thumbnail"] = None
|
thumbs: List["types.Thumbnail"] = None,
|
||||||
|
cover: "types.Photo" = None,
|
||||||
|
start_timestamp: int = None,
|
||||||
):
|
):
|
||||||
super().__init__(client)
|
super().__init__(client)
|
||||||
|
|
||||||
|
|
@ -100,6 +107,8 @@ class Video(Object):
|
||||||
self.ttl_seconds = ttl_seconds
|
self.ttl_seconds = ttl_seconds
|
||||||
self.date = date
|
self.date = date
|
||||||
self.thumbs = thumbs
|
self.thumbs = thumbs
|
||||||
|
self.cover = cover
|
||||||
|
self.start_timestamp = start_timestamp
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(
|
def _parse(
|
||||||
|
|
@ -107,7 +116,9 @@ class Video(Object):
|
||||||
video: "raw.types.Document",
|
video: "raw.types.Document",
|
||||||
video_attributes: "raw.types.DocumentAttributeVideo",
|
video_attributes: "raw.types.DocumentAttributeVideo",
|
||||||
file_name: str,
|
file_name: str,
|
||||||
ttl_seconds: int = None
|
ttl_seconds: int = None,
|
||||||
|
cover = None,
|
||||||
|
start_timestamp: int = None
|
||||||
) -> "Video":
|
) -> "Video":
|
||||||
return Video(
|
return Video(
|
||||||
file_id=FileId(
|
file_id=FileId(
|
||||||
|
|
@ -131,5 +142,7 @@ class Video(Object):
|
||||||
date=utils.timestamp_to_datetime(video.date),
|
date=utils.timestamp_to_datetime(video.date),
|
||||||
ttl_seconds=ttl_seconds,
|
ttl_seconds=ttl_seconds,
|
||||||
thumbs=types.Thumbnail._parse(client, video),
|
thumbs=types.Thumbnail._parse(client, video),
|
||||||
|
cover=types.Photo._parse(client, cover),
|
||||||
|
start_timestamp=start_timestamp,
|
||||||
client=client
|
client=client
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -50,6 +50,7 @@ from .username import Username
|
||||||
from .forum_topic import ForumTopic
|
from .forum_topic import ForumTopic
|
||||||
from .forum_topic_created import ForumTopicCreated
|
from .forum_topic_created import ForumTopicCreated
|
||||||
from .forum_topic_closed import ForumTopicClosed
|
from .forum_topic_closed import ForumTopicClosed
|
||||||
|
from .forum_topic_deleted import ForumTopicDeleted
|
||||||
from .forum_topic_reopened import ForumTopicReopened
|
from .forum_topic_reopened import ForumTopicReopened
|
||||||
from .forum_topic_edited import ForumTopicEdited
|
from .forum_topic_edited import ForumTopicEdited
|
||||||
from .general_forum_topic_hidden import GeneralTopicHidden
|
from .general_forum_topic_hidden import GeneralTopicHidden
|
||||||
|
|
@ -88,6 +89,7 @@ __all__ = [
|
||||||
"ForumTopic",
|
"ForumTopic",
|
||||||
"ForumTopicCreated",
|
"ForumTopicCreated",
|
||||||
"ForumTopicClosed",
|
"ForumTopicClosed",
|
||||||
|
"ForumTopicDeleted",
|
||||||
"ForumTopicReopened",
|
"ForumTopicReopened",
|
||||||
"ForumTopicEdited",
|
"ForumTopicEdited",
|
||||||
"GeneralTopicHidden",
|
"GeneralTopicHidden",
|
||||||
|
|
|
||||||
|
|
@ -123,7 +123,9 @@ class ForumTopic(Object):
|
||||||
#self.draft = draft //todo
|
#self.draft = draft //todo
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse(forum_topic: "raw.types.forum_topic") -> "ForumTopic":
|
def _parse(forum_topic: "raw.types.ForumTopic") -> "ForumTopic":
|
||||||
|
if isinstance(forum_topic, raw.types.ForumTopicDeleted):
|
||||||
|
return types.ForumTopicDeleted._parse(forum_topic)
|
||||||
from_id = forum_topic.from_id
|
from_id = forum_topic.from_id
|
||||||
if isinstance(from_id, raw.types.PeerChannel):
|
if isinstance(from_id, raw.types.PeerChannel):
|
||||||
peer = types.PeerChannel._parse(from_id)
|
peer = types.PeerChannel._parse(from_id)
|
||||||
|
|
|
||||||
45
pyrogram/types/user_and_chats/forum_topic_deleted.py
Normal file
45
pyrogram/types/user_and_chats/forum_topic_deleted.py
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Pyrofork - Telegram MTProto API Client Library for Python
|
||||||
|
# Copyright (C) 2022-present Mayuri-Chan <https://github.com/Mayuri-Chan>
|
||||||
|
#
|
||||||
|
# This file is part of Pyrofork.
|
||||||
|
#
|
||||||
|
# Pyrofork 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.
|
||||||
|
#
|
||||||
|
# Pyrofork 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 Pyrofork. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
|
||||||
|
from pyrogram import raw, types
|
||||||
|
from typing import Union
|
||||||
|
from ..object import Object
|
||||||
|
|
||||||
|
|
||||||
|
class ForumTopicDeleted(Object):
|
||||||
|
"""A deleted forum topic.
|
||||||
|
|
||||||
|
Parameters:
|
||||||
|
id (``Integer``):
|
||||||
|
Id of the topic
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(
|
||||||
|
self,
|
||||||
|
*,
|
||||||
|
id: int
|
||||||
|
):
|
||||||
|
super().__init__()
|
||||||
|
|
||||||
|
self.id = id
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _parse(forum_topic: "raw.types.ForumTopicDeleted") -> "ForumTopicDeleted":
|
||||||
|
return ForumTopicDeleted(
|
||||||
|
id=getattr(forum_topic,"id", None)
|
||||||
|
)
|
||||||
Loading…
Reference in a new issue