From ddf90f26cf6ca5113548187fad87e7fafef492c2 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 19:18:59 +0700 Subject: [PATCH 01/39] pyrofork: Update API schema to Layer 204 Signed-off-by: wulan17 --- compiler/api/source/main_api.tl | 45 +++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 19 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index e3197d70..92956c78 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -108,7 +108,7 @@ userStatusLastMonth#65899777 flags:# by_me:flags.0?true = UserStatus; chatEmpty#29562865 id:long = Chat; chat#41cbf256 flags:# creator:flags.0?true left:flags.2?true deactivated:flags.5?true call_active:flags.23?true call_not_empty:flags.24?true noforwards:flags.25?true id:long title:string photo:ChatPhoto participants_count:int date:int version:int migrated_to:flags.6?InputChannel admin_rights:flags.14?ChatAdminRights default_banned_rights:flags.18?ChatBannedRights = Chat; chatForbidden#6592a1a7 id:long title:string = Chat; -channel#7482147e flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long = Chat; +channel#fe685355 flags:# creator:flags.0?true left:flags.2?true broadcast:flags.5?true verified:flags.7?true megagroup:flags.8?true restricted:flags.9?true signatures:flags.11?true min:flags.12?true scam:flags.19?true has_link:flags.20?true has_geo:flags.21?true slowmode_enabled:flags.22?true call_active:flags.23?true call_not_empty:flags.24?true fake:flags.25?true gigagroup:flags.26?true noforwards:flags.27?true join_to_send:flags.28?true join_request:flags.29?true forum:flags.30?true flags2:# stories_hidden:flags2.1?true stories_hidden_min:flags2.2?true stories_unavailable:flags2.3?true signature_profiles:flags2.12?true autotranslation:flags2.15?true broadcast_messages_allowed:flags2.16?true monoforum:flags2.17?true forum_tabs:flags2.19?true id:long access_hash:flags.13?long title:string username:flags.6?string photo:ChatPhoto date:int restriction_reason:flags.9?Vector admin_rights:flags.14?ChatAdminRights banned_rights:flags.15?ChatBannedRights default_banned_rights:flags.18?ChatBannedRights participants_count:flags.17?int usernames:flags2.0?Vector stories_max_id:flags2.4?int color:flags2.7?PeerColor profile_color:flags2.8?PeerColor emoji_status:flags2.9?EmojiStatus level:flags2.10?int subscription_until_date:flags2.11?int bot_verification_icon:flags2.13?long send_paid_messages_stars:flags2.14?long linked_monoforum_id:flags2.18?long = Chat; channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; @@ -195,7 +195,7 @@ messageActionPrizeStars#b00c47a2 flags:# unclaimed:flags.0?true stars:long trans messageActionStarGift#4717e8a4 flags:# name_hidden:flags.0?true saved:flags.2?true converted:flags.3?true upgraded:flags.5?true refunded:flags.9?true can_upgrade:flags.10?true gift:StarGift message:flags.1?TextWithEntities convert_stars:flags.4?long upgrade_msg_id:flags.5?int upgrade_stars:flags.8?long from_id:flags.11?Peer peer:flags.12?Peer saved_id:flags.12?long = MessageAction; messageActionStarGiftUnique#2e3ae60e flags:# upgrade:flags.0?true transferred:flags.1?true saved:flags.2?true refunded:flags.5?true gift:StarGift can_export_at:flags.3?int transfer_stars:flags.4?long from_id:flags.6?Peer peer:flags.7?Peer saved_id:flags.7?long resale_stars:flags.8?long can_transfer_at:flags.9?int can_resell_at:flags.10?int = MessageAction; messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; -messageActionPaidMessagesPrice#bcd71419 stars:long = MessageAction; +messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; @@ -341,7 +341,7 @@ updateBotCallbackQuery#b9cfc48d flags:# query_id:long user_id:long peer:Peer msg updateEditMessage#e40370a3 message:Message pts:int pts_count:int = Update; updateInlineBotCallbackQuery#691e9052 flags:# query_id:long user_id:long msg_id:InputBotInlineMessageID chat_instance:long data:flags.0?bytes game_short_name:flags.1?string = Update; updateReadChannelOutbox#b75f99a9 channel_id:long max_id:int = Update; -updateDraftMessage#1b49ec6d flags:# peer:Peer top_msg_id:flags.0?int draft:DraftMessage = Update; +updateDraftMessage#edfc111e flags:# peer:Peer top_msg_id:flags.0?int saved_peer_id:flags.1?Peer draft:DraftMessage = Update; updateReadFeaturedStickers#571d2742 = Update; updateRecentStickers#9a422c20 = Update; updateConfig#a229dd06 = Update; @@ -357,10 +357,10 @@ updatePhoneCall#ab0f6b1e phone_call:PhoneCall = Update; updateLangPackTooLong#46560264 lang_code:string = Update; updateLangPack#56022f4d difference:LangPackDifference = Update; updateFavedStickers#e511996d = Update; -updateChannelReadMessagesContents#ea29055d flags:# channel_id:long top_msg_id:flags.0?int messages:Vector = Update; +updateChannelReadMessagesContents#25f324f7 flags:# channel_id:long top_msg_id:flags.0?int saved_peer_id:flags.1?Peer messages:Vector = Update; updateContactsReset#7084a7be = Update; updateChannelAvailableMessages#b23fc698 channel_id:long available_min_id:int = Update; -updateDialogUnreadMark#e16459c3 flags:# unread:flags.0?true peer:DialogPeer = Update; +updateDialogUnreadMark#b658f23e flags:# unread:flags.0?true peer:DialogPeer saved_peer_id:flags.1?Peer = Update; updateMessagePoll#aca1657b flags:# poll_id:long poll:flags.0?Poll results:PollResults = Update; updateChatDefaultBannedRights#54c01850 peer:Peer default_banned_rights:ChatBannedRights version:int = Update; updateFolderPeers#19360dc0 folder_peers:Vector pts:int pts_count:int = Update; @@ -394,7 +394,7 @@ updateGroupCallConnection#b783982 flags:# presentation:flags.0?true params:DataJ updateBotCommands#4d712f2e peer:Peer bot_id:long commands:Vector = Update; updatePendingJoinRequests#7063c3db peer:Peer requests_pending:int recent_requesters:Vector = Update; updateBotChatInviteRequester#11dfa986 peer:Peer date:int user_id:long about:string invite:ExportedChatInvite qts:int = Update; -updateMessageReactions#5e1b3cb8 flags:# peer:Peer msg_id:int top_msg_id:flags.0?int reactions:MessageReactions = Update; +updateMessageReactions#1e297bfa flags:# peer:Peer msg_id:int top_msg_id:flags.0?int saved_peer_id:flags.1?Peer reactions:MessageReactions = Update; updateAttachMenuBots#17b7a20b = Update; updateWebViewResultSent#1592b79d query_id:long = Update; updateBotMenuButton#14b85813 bot_id:long button:BotMenuButton = Update; @@ -442,6 +442,8 @@ updateBotPurchasedPaidMedia#283bd312 user_id:long payload:string qts:int = Updat updatePaidReactionPrivacy#8b725fce private:PaidReactionPrivacy = Update; updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; +updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; +updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -1647,8 +1649,9 @@ stories.storyViewsList#59d78fc5 flags:# count:int views_count:int forwards_count stories.storyViews#de9eed1d views:Vector users:Vector = stories.StoryViews; -inputReplyToMessage#22c0f6d5 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int = InputReplyTo; +inputReplyToMessage#b07038b0 flags:# reply_to_msg_id:int top_msg_id:flags.0?int reply_to_peer_id:flags.1?InputPeer quote_text:flags.2?string quote_entities:flags.3?Vector quote_offset:flags.4?int monoforum_peer_id:flags.5?InputPeer = InputReplyTo; inputReplyToStory#5881323a peer:InputPeer story_id:int = InputReplyTo; +inputReplyToMonoForum#69d66c45 monoforum_peer_id:InputPeer = InputReplyTo; exportedStoryLink#3fc9053b link:string = ExportedStoryLink; @@ -1721,6 +1724,7 @@ storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; +monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; @@ -2186,7 +2190,7 @@ messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; messages.sendMessage#fbf2340a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; messages.sendMedia#a550cd78 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.forwardMessages#bb9fa475 flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int allow_paid_stars:flags.21?long = Updates; +messages.forwardMessages#38f0188c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int allow_paid_stars:flags.21?long = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; @@ -2268,8 +2272,8 @@ messages.sendMultiMedia#1bf89d74 flags:# silent:flags.5?true background:flags.6? messages.uploadEncryptedFile#5057c497 peer:InputEncryptedChat file:InputEncryptedFile = EncryptedFile; messages.searchStickerSets#35705b8a flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; messages.getSplitRanges#1cff7e08 = Vector; -messages.markDialogUnread#c286d98f flags:# unread:flags.0?true peer:InputDialogPeer = Bool; -messages.getDialogUnreadMarks#22e24e22 = Vector; +messages.markDialogUnread#8c5006f8 flags:# unread:flags.0?true parent_peer:flags.1?InputPeer peer:InputDialogPeer = Bool; +messages.getDialogUnreadMarks#21202222 flags:# parent_peer:flags.0?InputPeer = Vector; messages.clearAllDrafts#7e58ee9c = Bool; messages.updatePinnedMessage#d2aaf7ec flags:# silent:flags.0?true unpin:flags.1?true pm_oneside:flags.2?true peer:InputPeer id:int = Updates; messages.sendVote#10ea6184 peer:InputPeer msg_id:int options:Vector = Updates; @@ -2299,7 +2303,7 @@ messages.getOldFeaturedStickers#7ed094a1 offset:int limit:int hash:long = messag messages.getReplies#22ddd30c peer:InputPeer msg_id:int offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; messages.getDiscussionMessage#446972fd peer:InputPeer msg_id:int = messages.DiscussionMessage; messages.readDiscussion#f731a9f4 peer:InputPeer msg_id:int read_max_id:int = Bool; -messages.unpinAllMessages#ee22b9a8 flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; +messages.unpinAllMessages#62dd747 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; messages.deleteChat#5bd0ee50 chat_id:long = Bool; messages.deletePhoneCallHistory#f9cbe409 flags:# revoke:flags.0?true = messages.AffectedFoundMessages; messages.checkHistoryImport#43fe19f3 import_head:string = messages.HistoryImportParsed; @@ -2330,8 +2334,8 @@ messages.setChatAvailableReactions#864b2581 flags:# peer:InputPeer available_rea messages.getAvailableReactions#18dea0ac hash:int = messages.AvailableReactions; messages.setDefaultReaction#4f47a016 reaction:Reaction = Bool; messages.translateText#63183030 flags:# peer:flags.0?InputPeer id:flags.0?Vector text:flags.1?Vector to_lang:string = messages.TranslatedText; -messages.getUnreadReactions#3223495b flags:# peer:InputPeer top_msg_id:flags.0?int offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; -messages.readReactions#54aa7f8e flags:# peer:InputPeer top_msg_id:flags.0?int = messages.AffectedHistory; +messages.getUnreadReactions#bd7f90ac flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer offset_id:int add_offset:int limit:int max_id:int min_id:int = messages.Messages; +messages.readReactions#9ec44f93 flags:# peer:InputPeer top_msg_id:flags.0?int saved_peer_id:flags.1?InputPeer = messages.AffectedHistory; messages.searchSentMedia#107e31a0 q:string filter:MessagesFilter limit:int = messages.Messages; messages.getAttachMenuBots#16fcc2cb hash:long = AttachMenuBots; messages.getAttachMenuBot#77216192 bot:InputUser = AttachMenuBotsBot; @@ -2363,9 +2367,9 @@ messages.getBotApp#34fdc5c3 app:InputBotApp hash:long = messages.BotApp; messages.requestAppWebView#53618bce flags:# write_allowed:flags.0?true compact:flags.7?true fullscreen:flags.8?true peer:InputPeer app:InputBotApp start_param:flags.1?string theme_params:flags.2?DataJSON platform:string = WebViewResult; messages.setChatWallPaper#8ffacae1 flags:# for_both:flags.3?true revert:flags.4?true peer:InputPeer wallpaper:flags.0?InputWallPaper settings:flags.2?WallPaperSettings id:flags.1?int = Updates; messages.searchEmojiStickerSets#92b4494c flags:# exclude_featured:flags.0?true q:string hash:long = messages.FoundStickerSets; -messages.getSavedDialogs#5381d21a flags:# exclude_pinned:flags.0?true offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; -messages.getSavedHistory#3d9a414d peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; -messages.deleteSavedHistory#6e98102b flags:# peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; +messages.getSavedDialogs#1e91fc99 flags:# exclude_pinned:flags.0?true parent_peer:flags.1?InputPeer offset_date:int offset_id:int offset_peer:InputPeer limit:int hash:long = messages.SavedDialogs; +messages.getSavedHistory#998ab009 flags:# parent_peer:flags.0?InputPeer peer:InputPeer offset_id:int offset_date:int add_offset:int limit:int max_id:int min_id:int hash:long = messages.Messages; +messages.deleteSavedHistory#4dc5085f flags:# parent_peer:flags.0?InputPeer peer:InputPeer max_id:int min_date:flags.2?int max_date:flags.3?int = messages.AffectedHistory; messages.getPinnedSavedDialogs#d63d94e0 = messages.SavedDialogs; messages.toggleSavedDialogPin#ac81bbde flags:# pinned:flags.0?true peer:InputDialogPeer = Bool; messages.reorderPinnedSavedDialogs#8b716587 flags:# force:flags.0?true order:Vector = Bool; @@ -2400,6 +2404,8 @@ messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; +messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; +messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2488,7 +2494,7 @@ channels.toggleJoinRequest#4c2985b6 channel:InputChannel enabled:Bool = Updates; channels.reorderUsernames#b45ced1d channel:InputChannel order:Vector = Bool; channels.toggleUsername#50f24105 channel:InputChannel username:string active:Bool = Bool; channels.deactivateAllUsernames#a245dd3 channel:InputChannel = Bool; -channels.toggleForum#a4298b29 channel:InputChannel enabled:Bool = Updates; +channels.toggleForum#3ff75734 channel:InputChannel enabled:Bool tabs:Bool = Updates; channels.createForumTopic#f40c0224 flags:# channel:InputChannel title:string icon_color:flags.0?int icon_emoji_id:flags.3?long random_id:long send_as:flags.2?InputPeer = Updates; channels.getForumTopics#de560d1 flags:# channel:InputChannel q:flags.0?string offset_date:int offset_id:int offset_topic:int limit:int = messages.ForumTopics; channels.getForumTopicsByID#b0831eb9 channel:InputChannel topics:Vector = messages.ForumTopics; @@ -2507,8 +2513,9 @@ channels.setBoostsToUnblockRestrictions#ad399cee channel:InputChannel boosts:int channels.setEmojiStickers#3cd930b7 channel:InputChannel stickerset:InputStickerSet = Bool; channels.restrictSponsoredMessages#9ae91519 channel:InputChannel restricted:Bool = Updates; channels.searchPosts#d19f987b hashtag:string offset_rate:int offset_peer:InputPeer offset_id:int limit:int = messages.Messages; -channels.updatePaidMessagesPrice#fc84653f channel:InputChannel send_paid_messages_stars:long = Updates; +channels.updatePaidMessagesPrice#4b12327b flags:# broadcast_messages_allowed:flags.0?true channel:InputChannel send_paid_messages_stars:long = Updates; channels.toggleAutotranslation#167fc0a1 channel:InputChannel enabled:Bool = Updates; +channels.getMessageAuthor#ece2a0e6 channel:InputChannel id:int = User; bots.sendCustomRequest#aa2769ed custom_method:string params:DataJSON = DataJSON; bots.answerWebhookJSONQuery#e6213f4d query_id:long data:DataJSON = Bool; @@ -2716,4 +2723,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; -// LAYER 203 +// LAYER 204 From 71c0a1176ace15b6ceda79911138c749566b113c Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 19:25:55 +0700 Subject: [PATCH 02/39] pyrofork: fix typo in filters Signed-off-by: wulan17 --- pyrogram/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index 3c3bc650..d152e32a 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -1108,7 +1108,7 @@ class chat(Filter, set): else: is_usernames_in_filters = False if message.chat.usernames: - for username in message._chat.usernames: + for username in message.chat.usernames: if ( username.username in self or username.username.lower() in self From 8880a92483430941e87938b9533587f7c0134a7f Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 19:30:04 +0700 Subject: [PATCH 03/39] pyrofork: types: Wallpaper: Make document optional Signed-off-by: wulan17 --- pyrogram/types/messages_and_media/wallpaper.py | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pyrogram/types/messages_and_media/wallpaper.py b/pyrogram/types/messages_and_media/wallpaper.py index e5ea024b..44a7a33e 100644 --- a/pyrogram/types/messages_and_media/wallpaper.py +++ b/pyrogram/types/messages_and_media/wallpaper.py @@ -54,7 +54,7 @@ class Wallpaper(Object): self, id: int, slug: str, - document: "types.Document", + document: "types.Document" = None, is_creator: bool = None, is_default: bool = None, is_pattern: bool = None, @@ -73,7 +73,9 @@ class Wallpaper(Object): @staticmethod def _parse(client: "pyrogram.Client", wallpaper: "raw.base.WallPaper") -> "Wallpaper": - doc = wallpaper.document + doc = None + if not isinstance(wallpaper, raw.types.WallPaperNoFile): + doc = wallpaper.document attributes = {type(i): i for i in doc.attributes} file_name = getattr( @@ -84,7 +86,7 @@ class Wallpaper(Object): return Wallpaper( id=wallpaper.id, slug=wallpaper.slug, - document=types.Document._parse(client, doc, file_name), + document=types.Document._parse(client, doc, file_name) if doc is not None else None, is_creator=getattr(wallpaper, "creator", None), is_default=getattr(wallpaper, "default", None), is_pattern=getattr(wallpaper, "pattern", None), From 83f3f5268175a3d2f2b6e5cc3fbb2f9592c9c362 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 19:57:41 +0700 Subject: [PATCH 04/39] pyrofork: Refactor Message.link Signed-off-by: wulan17 --- pyrogram/types/messages_and_media/message.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 4776410d..e91d915c 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -1314,9 +1314,14 @@ class Message(Object, Update): self.chat.type in (enums.ChatType.GROUP, enums.ChatType.SUPERGROUP, enums.ChatType.CHANNEL) and self.chat.username ): + if self.chat.type == enums.ChatType.SUPERGROUP and self.message_thread_id: + return f"https://t.me/{self.chat.username}/{self.message_thread_id}/{self.id}" return f"https://t.me/{self.chat.username}/{self.id}" - else: - return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.id}" + if self.chat.type == enums.ChatType.PRIVATE: + return f"tg://openmessage?user_id={self.from_user.id}&message_id={self.id}" + if self.message_thread_id: + return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.message_thread_id}/{self.id}" + return f"https://t.me/c/{utils.get_channel_id(self.chat.id)}/{self.id}" @property def content(self) -> str: From 3d343a49ff2be468b5fbf91688e400eaa88361f2 Mon Sep 17 00:00:00 2001 From: uNickz <52837683+uNickz@users.noreply.github.com> Date: Mon, 7 Oct 2024 11:45:46 +0200 Subject: [PATCH 05/39] pyrofork: Add file_name param on InputMedia * Add file_name param on InputMedia Add file_name param on: - InputMediaVideo - InputMediaAudio - InputMediaDocument --------- Co-authored-by: KurimuzonAkuma <31959970+KurimuzonAkuma@users.noreply.github.com> Signed-off-by: wulan17 --- pyrogram/methods/messages/send_media_group.py | 12 ++++++------ pyrogram/types/input_media/input_media_audio.py | 8 +++++++- pyrogram/types/input_media/input_media_document.py | 8 +++++++- pyrogram/types/input_media/input_media_video.py | 6 ++++++ 4 files changed, 26 insertions(+), 8 deletions(-) diff --git a/pyrogram/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py index ca66cab6..a6a14021 100644 --- a/pyrogram/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -271,7 +271,7 @@ class SendMediaGroup: w=i.width, h=i.height ), - raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)), + raw.types.DocumentAttributeFilename(file_name=i.file_name or os.path.basename(i.media)), ] if is_animation: attributes.append(raw.types.DocumentAttributeAnimated()) @@ -339,7 +339,7 @@ class SendMediaGroup: w=i.width, h=i.height ), - raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "video.mp4")), + raw.types.DocumentAttributeFilename(file_name=i.file_name or getattr(i.media, "name", "video.mp4")), ], ), ), @@ -371,7 +371,7 @@ class SendMediaGroup: performer=i.performer, title=i.title ), - raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)), + raw.types.DocumentAttributeFilename(file_name=i.file_name or os.path.basename(i.media)), ], ), ), @@ -419,7 +419,7 @@ class SendMediaGroup: performer=i.performer, title=i.title ), - raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "audio.mp3")), + raw.types.DocumentAttributeFilename(file_name=i.file_name or getattr(i.media, "name", "audio.mp3")), ], ), ), @@ -445,7 +445,7 @@ class SendMediaGroup: file=file, thumb=thumb, attributes=[ - raw.types.DocumentAttributeFilename(file_name=os.path.basename(i.media)), + raw.types.DocumentAttributeFilename(file_name=i.file_name or os.path.basename(i.media)), ], ), ), @@ -490,7 +490,7 @@ class SendMediaGroup: file=file, thumb=thumb, attributes=[ - raw.types.DocumentAttributeFilename(file_name=getattr(i.media, "name", "file.zip")), + raw.types.DocumentAttributeFilename(file_name=i.file_name or getattr(i.media, "name", "file.zip")), ], ), ), diff --git a/pyrogram/types/input_media/input_media_audio.py b/pyrogram/types/input_media/input_media_audio.py index ffd5d70d..24feac1f 100644 --- a/pyrogram/types/input_media/input_media_audio.py +++ b/pyrogram/types/input_media/input_media_audio.py @@ -62,6 +62,10 @@ class InputMediaAudio(InputMedia): title (``str``, *optional*): Title of the audio + + file_name (``str``, *optional*): + File name of the audio sent. + Defaults to file's path basename. """ def __init__( @@ -73,7 +77,8 @@ class InputMediaAudio(InputMedia): caption_entities: List[MessageEntity] = None, duration: int = 0, performer: str = "", - title: str = "" + title: str = "", + file_name: str = None ): super().__init__(media, caption, parse_mode, caption_entities) @@ -81,3 +86,4 @@ class InputMediaAudio(InputMedia): self.duration = duration self.performer = performer self.title = title + self.file_name = file_name diff --git a/pyrogram/types/input_media/input_media_document.py b/pyrogram/types/input_media/input_media_document.py index 766d17f2..feca4953 100644 --- a/pyrogram/types/input_media/input_media_document.py +++ b/pyrogram/types/input_media/input_media_document.py @@ -51,6 +51,10 @@ class InputMediaDocument(InputMedia): caption_entities (List of :obj:`~pyrogram.types.MessageEntity`): List of special entities that appear in the caption, which can be specified instead of *parse_mode*. + + file_name (``str``, *optional*): + File name of the document sent. + Defaults to file's path basename. """ def __init__( @@ -59,8 +63,10 @@ class InputMediaDocument(InputMedia): thumb: str = None, caption: str = "", parse_mode: Optional["enums.ParseMode"] = None, - caption_entities: List[MessageEntity] = None + caption_entities: List[MessageEntity] = None, + file_name: str = None ): super().__init__(media, caption, parse_mode, caption_entities) self.thumb = thumb + self.file_name = file_name diff --git a/pyrogram/types/input_media/input_media_video.py b/pyrogram/types/input_media/input_media_video.py index 0b4c6aa8..bc7a716b 100644 --- a/pyrogram/types/input_media/input_media_video.py +++ b/pyrogram/types/input_media/input_media_video.py @@ -62,6 +62,10 @@ class InputMediaVideo(InputMedia): duration (``int``, *optional*): Video duration. + file_name (``str``, *optional*): + File name of the video sent. + Defaults to file's path basename. + supports_streaming (``bool``, *optional*): Pass True, if the uploaded video is suitable for streaming. @@ -79,6 +83,7 @@ class InputMediaVideo(InputMedia): width: int = 0, height: int = 0, duration: int = 0, + file_name: str = None, supports_streaming: bool = True, has_spoiler: bool = None, ): @@ -88,5 +93,6 @@ class InputMediaVideo(InputMedia): self.width = width self.height = height self.duration = duration + self.file_name = file_name self.supports_streaming = supports_streaming self.has_spoiler = has_spoiler From 78467e30a2a96a1da1e0a43300185cecaa4d0e53 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Tue, 10 Jun 2025 21:49:47 +0700 Subject: [PATCH 06/39] pyrofork: Add search_gifts_for_resale, send_resold_gift, set_gift_resale_price, set_pinned_gifts methods Co-authored-by: "ALi.w" Signed-off-by: wulan17 --- compiler/docs/compiler.py | 4 + docs/source/api/enums/GiftForResaleOrder.rst | 8 ++ pyrogram/enums/__init__.py | 2 + pyrogram/enums/gift_for_resale_order.py | 35 ++++++ pyrogram/methods/payments/__init__.py | 8 ++ .../payments/search_gifts_for_resale.py | 110 ++++++++++++++++++ pyrogram/methods/payments/send_resold_gift.py | 89 ++++++++++++++ .../methods/payments/set_gift_resale_price.py | 82 +++++++++++++ pyrogram/methods/payments/set_pinned_gifts.py | 95 +++++++++++++++ 9 files changed, 433 insertions(+) create mode 100644 docs/source/api/enums/GiftForResaleOrder.rst create mode 100644 pyrogram/enums/gift_for_resale_order.py create mode 100644 pyrogram/methods/payments/search_gifts_for_resale.py create mode 100644 pyrogram/methods/payments/send_resold_gift.py create mode 100644 pyrogram/methods/payments/set_gift_resale_price.py create mode 100644 pyrogram/methods/payments/set_pinned_gifts.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 10e20a1f..3a9e913c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -365,11 +365,15 @@ def pyrogram_api(): get_chat_gifts hide_gift refund_star_payment + search_gifts_for_resale send_invoice send_paid_media send_paid_reaction send_payment_form send_gift + send_resold_gift + set_gift_resale_price + set_pinned_gift show_gift transfer_gift upgrade_gift diff --git a/docs/source/api/enums/GiftForResaleOrder.rst b/docs/source/api/enums/GiftForResaleOrder.rst new file mode 100644 index 00000000..7d8d0b46 --- /dev/null +++ b/docs/source/api/enums/GiftForResaleOrder.rst @@ -0,0 +1,8 @@ +GiftAttributeType +================= + +.. autoclass:: pyrogram.enums.GiftForResaleOrder() + :members: + +.. raw:: html + :file: ./cleanup.html diff --git a/pyrogram/enums/__init__.py b/pyrogram/enums/__init__.py index aac9db33..c67f64b7 100644 --- a/pyrogram/enums/__init__.py +++ b/pyrogram/enums/__init__.py @@ -27,6 +27,7 @@ from .chat_type import ChatType from .client_platform import ClientPlatform from .folder_color import FolderColor from .gift_attribute_type import GiftAttributeType +from .gift_for_resale_order import GiftForResaleOrder from .listerner_types import ListenerTypes from .message_entity_type import MessageEntityType from .message_media_type import MessageMediaType @@ -55,6 +56,7 @@ __all__ = [ 'ClientPlatform', 'FolderColor', 'GiftAttributeType', + 'GiftForResaleOrder', 'ListenerTypes', 'MessageEntityType', 'MessageMediaType', diff --git a/pyrogram/enums/gift_for_resale_order.py b/pyrogram/enums/gift_for_resale_order.py new file mode 100644 index 00000000..403b3691 --- /dev/null +++ b/pyrogram/enums/gift_for_resale_order.py @@ -0,0 +1,35 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present 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 . + +from enum import auto + +from .auto_name import AutoName + + +class GiftForResaleOrder(AutoName): + """Describes order in which upgraded gifts for resale will be sorted. Used in :meth:`~pyrogram.Client.search_gifts_for_resale`.""" + + PRICE = auto() + "The gifts will be sorted by their price from the lowest to the highest" + + CHANGE_DATE = auto() + "The gifts will be sorted by the last date when their price was changed from the newest to the oldest" + + NUMBER = auto() + "The gifts will be sorted by their number from the smallest to the largest" diff --git a/pyrogram/methods/payments/__init__.py b/pyrogram/methods/payments/__init__.py index d67a26aa..5164f94c 100644 --- a/pyrogram/methods/payments/__init__.py +++ b/pyrogram/methods/payments/__init__.py @@ -31,11 +31,15 @@ from .get_chat_gifts_count import GetChatGiftsCount from .get_chat_gifts import GetChatGifts from .hide_gift import HideGift from .refund_stars_payment import RefundStarPayment +from .search_gifts_for_resale import SearchGiftsForResale from .send_invoice import SendInvoice from .send_paid_media import SendPaidMedia from .send_paid_reaction import SendPaidReaction from .send_payment_form import SendPaymentForm from .send_gift import SendGift +from .send_resold_gift import SendResoldGift +from .set_gift_resale_price import SetGiftResalePrice +from .set_pinned_gift import SetPinnedGift from .show_gift import ShowGift from .transfer_gift import TransferGift from .upgrade_gift import UpgradeGift @@ -55,11 +59,15 @@ class Payments( GetChatGifts, HideGift, RefundStarPayment, + SearchGiftsForResale, SendPaidReaction, SendPaidMedia, SendInvoice, SendPaymentForm, SendGift, + SendResoldGift, + SetGiftResalePrice, + SetPinnedGift, ShowGift, TransferGift, UpgradeGift diff --git a/pyrogram/methods/payments/search_gifts_for_resale.py b/pyrogram/methods/payments/search_gifts_for_resale.py new file mode 100644 index 00000000..c576766c --- /dev/null +++ b/pyrogram/methods/payments/search_gifts_for_resale.py @@ -0,0 +1,110 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present 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 . + +from typing import List, Optional + +import pyrogram +from pyrogram import enums, raw, types + + +class SearchGiftsForResale: + async def search_gifts_for_resale( + self: "pyrogram.Client", + gift_id: int, + order: "enums.GiftForResaleOrder" = enums.GiftForResaleOrder.CHANGE_DATE, + attributes: Optional[List["types.UpgradedGiftAttributeId"]] = None, + limit: int = 0, + offset: str = "" + ): + """Get upgraded gifts that can be bought from other owners. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + gift_id (``int``): + Identifier of the regular gift that was upgraded to a unique gift. + + order (:obj:`~pyrogram.enums.GiftForResaleOrder`): + Order in which the results will be sorted. + + attributes (List of :obj:`~pyrogram.types.UpgradedGiftAttributeId`, *optional*): + Attributes used to filter received gifts. + If multiple attributes of the same type are specified, then all of them are allowed. + If none attributes of specific type are specified, then all values for this attribute type are allowed. + + limit (``int``, *optional*): + The maximum number of gifts to return. Default is 0 (no limit). + + offset (``str``, *optional*): + The offset from which to start returning results. Default is "" (no offset). + + Returns: + ``Generator``: A generator yielding :obj:`~pyrogram.types.Gift` objects. + + Example: + .. code-block:: python + + async for gift in app.search_gifts_for_resale(gift_id=123456): + print(gift) + + # Buy first gift from resale market + async for gift in app.search_gifts_for_resale(gift_id=123456, limit=1): + await app.send_resold_gift(gift_link=gift.link, new_owner_chat_id="me") # or just use await gift.buy() + """ + current = 0 + total = abs(limit) or (1 << 31) - 1 + limit = min(100, total) + + while True: + r = await self.invoke( + raw.functions.payments.GetResaleStarGifts( + gift_id=gift_id, + offset=offset, + limit=limit, + sort_by_price=order == enums.GiftForResaleOrder.PRICE, + sort_by_num=order == enums.GiftForResaleOrder.NUMBER, + attributes=[attr.write() for attr in attributes] if attributes else None, + + ), + sleep_threshold=60 + ) + + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + + gifts = [ + await types.Gift._parse(self, gift, users, chats) + for gift in r.gifts + ] + + if not gifts: + return + + for gift in gifts: + yield gift + + current += 1 + + if current >= total: + return + + offset = r.next_offset + + if not offset: + return diff --git a/pyrogram/methods/payments/send_resold_gift.py b/pyrogram/methods/payments/send_resold_gift.py new file mode 100644 index 00000000..21f66489 --- /dev/null +++ b/pyrogram/methods/payments/send_resold_gift.py @@ -0,0 +1,89 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present 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 . + + +from typing import Optional, Union + +import pyrogram +from pyrogram import raw, types, utils + + +class SendResoldGift: + async def send_resold_gift( + self: "pyrogram.Client", + gift_link: str, + new_owner_chat_id: Union[int, str], + ) -> Optional["types.Message"]: + """Send an upgraded gift that is available for resale to another user or channel chat. + + .. note:: + + Gifts already owned by the current user must be transferred using :meth:`~pyrogram.Client.transfer_gift` and can't be passed to this method. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + gift_link (``str``): + Link to the gift. + + new_owner_chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat you want to transfer the star gift to. + 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). + + Returns: + :obj:`~pyrogram.types.Message`: On success, the sent message is returned. + + Example: + .. code-block:: python + + # Transfer gift to another user + await app.send_resold_gift(gift_link="https://t.me/nft/NekoHelmet-9215", new_owner_chat_id=123) + """ + match = self.UPGRADED_GIFT_RE.match(gift_link) + + if not match: + raise ValueError( + "Invalid gift link provided." + ) + + peer = await self.resolve_peer(new_owner_chat_id) + + invoice = raw.types.InputInvoiceStarGiftResale( + slug=match.group(1), + to_id=peer + ) + + r = await self.invoke( + raw.functions.payments.SendStarsForm( + form_id=(await self.invoke( + raw.functions.payments.GetPaymentForm( + invoice=invoice + ), + )).form_id, + invoice=invoice + ), + ) + + messages = await utils.parse_messages( + client=self, + messages=r.updates if isinstance(r, raw.types.payments.PaymentResult) else r + ) + + return messages[0] if messages else None diff --git a/pyrogram/methods/payments/set_gift_resale_price.py b/pyrogram/methods/payments/set_gift_resale_price.py new file mode 100644 index 00000000..52ce7d6e --- /dev/null +++ b/pyrogram/methods/payments/set_gift_resale_price.py @@ -0,0 +1,82 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present 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 . + +import re + +import pyrogram +from pyrogram import raw + + +class SetGiftResalePrice: + async def set_gift_resale_price( + self: "pyrogram.Client", + owned_gift_id: str, + resale_star_count: int + ) -> bool: + """Change resale price of a unique gift owned by the current user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + owned_gift_id (``str``): + Unique identifier of the target gift. + For a user gift, you can use the message ID (int) of the gift message. + For a channel gift, you can use the packed format `chatID_savedID` (str). + For a upgraded gift, you can use the gift link. + + resale_star_count (``int``): + The new price for the unique gift. Pass 0 to disallow gift resale. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Change resale price of a unique gift + await app.set_gift_resale_price(owned_gift_id="123456", resale_star_count=100) + """ + if not isinstance(owned_gift_id, str): + raise ValueError(f"owned_gift_id has to be str, but {type(owned_gift_id)} was provided") + + saved_gift_match = re.match(r"^(-\d+)_(\d+)$", owned_gift_id) + slug_match = self.UPGRADED_GIFT_RE.match(owned_gift_id) + + if saved_gift_match: + stargift = raw.types.InputSavedStarGiftChat( + peer=await self.resolve_peer(saved_gift_match.group(1)), + saved_id=int(saved_gift_match.group(2)) + ) + elif slug_match: + stargift = raw.types.InputSavedStarGiftSlug( + slug=slug_match.group(1) + ) + else: + stargift = raw.types.InputSavedStarGiftUser( + msg_id=int(owned_gift_id) + ) + + await self.invoke( + raw.functions.payments.UpdateStarGiftPrice( + stargift=stargift, + resell_stars=resale_star_count + ) + ) + + return True diff --git a/pyrogram/methods/payments/set_pinned_gifts.py b/pyrogram/methods/payments/set_pinned_gifts.py new file mode 100644 index 00000000..56352d43 --- /dev/null +++ b/pyrogram/methods/payments/set_pinned_gifts.py @@ -0,0 +1,95 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present 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 . + +import re +from typing import List, Union + +import pyrogram +from pyrogram import raw + + +class SetPinnedGifts: + async def set_pinned_gifts( + self: "pyrogram.Client", + owner_id: Union[int, str], + owned_gift_ids: List[str], + ) -> bool: + """Change the list of pinned gifts on the current user. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + owner_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). + + owned_gift_ids (List of ``str``): + New list of pinned gifts. + All gifts must be upgraded and saved on the profile page first. + For a user gift, you can use the message ID (int) of the gift message. + For a channel gift, you can use the packed format `chatID_savedID` (str). + For a upgraded gift, you can use the gift link. + + Returns: + ``bool``: On success, True is returned. + + Example: + .. code-block:: python + + # Set pinned gifts in user profile + await app.set_pinned_gifts(received_gift_ids=["123", "456"]) + """ + stargifts = [] + + for gift in owned_gift_ids: + if not isinstance(gift, str): + raise ValueError(f"gift id has to be str, but {type(gift)} was provided") + + saved_gift_match = re.match(r"^(-\d+)_(\d+)$", gift) + slug_match = self.UPGRADED_GIFT_RE.match(gift) + + if saved_gift_match: + stargifts.append( + raw.types.InputSavedStarGiftChat( + peer=await self.resolve_peer(saved_gift_match.group(1)), + saved_id=int(saved_gift_match.group(2)) + ) + ) + elif slug_match: + stargifts.append( + raw.types.InputSavedStarGiftSlug( + slug=slug_match.group(1) + ) + ) + else: + stargifts.append( + raw.types.InputSavedStarGiftUser( + msg_id=int(gift) + ) + ) + + r = await self.invoke( + raw.functions.payments.ToggleStarGiftsPinnedToTop( + peer=await self.resolve_peer(owner_id), + stargift=stargifts + ) + ) + + return r From a9c4ef4c2e9feb934f96c85c50d27922fce02f56 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Thu, 28 Dec 2023 18:06:46 +0300 Subject: [PATCH 07/39] pyrofork: Add privileges to RequestPeer buttons Signed-off-by: wulan17 --- .../bots_and_keyboards/keyboard_button.py | 57 +++++++++++++++++-- .../request_peer_type_channel.py | 27 ++++++--- .../request_peer_type_chat.py | 30 +++++++--- 3 files changed, 94 insertions(+), 20 deletions(-) diff --git a/pyrogram/types/bots_and_keyboards/keyboard_button.py b/pyrogram/types/bots_and_keyboards/keyboard_button.py index cf40bf2b..f565a64a 100644 --- a/pyrogram/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/keyboard_button.py @@ -99,15 +99,21 @@ class KeyboardButton(Object): if isinstance(b, raw.types.KeyboardButtonRequestPeer): if isinstance(b.peer_type, raw.types.RequestPeerTypeBroadcast): + user_privileges = getattr(b.peer_type, "user_admin_rights", None) + bot_privileges = getattr(b.peer_type, "bot_admin_rights", None) return KeyboardButton( text=b.text, request_chat=types.RequestPeerTypeChannel( is_creator=b.peer_type.creator, is_username=b.peer_type.has_username, - max=b.max_quantity + max=b.max_quantity, + user_privileges=user_privileges, + bot_privileges=bot_privileges ) ) if isinstance(b.peer_type, raw.types.RequestPeerTypeChat): + user_privileges = getattr(b.peer_type, "user_admin_rights", None) + bot_privileges = getattr(b.peer_type, "bot_admin_rights", None) return KeyboardButton( text=b.text, request_chat=types.RequestPeerTypeChat( @@ -115,7 +121,9 @@ class KeyboardButton(Object): is_bot_participant=b.peer_type.bot_participant, is_username=b.peer_type.has_username, is_forum=b.peer_type.forum, - max=b.max_quantity + max=b.max_quantity, + user_privileges=user_privileges, + bot_privileges=bot_privileges ) ) @@ -135,13 +143,52 @@ class KeyboardButton(Object): elif self.request_location: return raw.types.KeyboardButtonRequestGeoLocation(text=self.text) elif self.request_chat: + user_privileges = self.request_peer.user_privileges + bot_privileges = self.request_peer.bot_privileges + + user_admin_rights = raw.types.ChatAdminRights( + change_info=user_privileges.can_change_info, + post_messages=user_privileges.can_post_messages, + post_stories=user_privileges.can_post_stories, + edit_messages=user_privileges.can_edit_messages, + edit_stories=user_privileges.can_post_stories, + delete_messages=user_privileges.can_delete_messages, + delete_stories=user_privileges.can_delete_stories, + ban_users=user_privileges.can_restrict_members, + invite_users=user_privileges.can_invite_users, + pin_messages=user_privileges.can_pin_messages, + add_admins=user_privileges.can_promote_members, + anonymous=user_privileges.is_anonymous, + manage_call=user_privileges.can_manage_video_chats, + other=user_privileges.can_manage_chat + ) if user_privileges else None + + bot_admin_rights = raw.types.ChatAdminRights( + change_info=bot_privileges.can_change_info, + post_messages=bot_privileges.can_post_messages, + post_stories=bot_privileges.can_post_stories, + edit_messages=bot_privileges.can_edit_messages, + edit_stories=bot_privileges.can_post_stories, + delete_messages=bot_privileges.can_delete_messages, + delete_stories=bot_privileges.can_delete_stories, + ban_users=bot_privileges.can_restrict_members, + invite_users=bot_privileges.can_invite_users, + pin_messages=bot_privileges.can_pin_messages, + add_admins=bot_privileges.can_promote_members, + anonymous=bot_privileges.is_anonymous, + manage_call=bot_privileges.can_manage_video_chats, + other=bot_privileges.can_manage_chat + ) if bot_privileges else None + if isinstance(self.request_chat, types.RequestPeerTypeChannel): return raw.types.InputKeyboardButtonRequestPeer( text=self.text, button_id=self.request_chat.button_id, peer_type=raw.types.RequestPeerTypeBroadcast( creator=self.request_chat.is_creator, - has_username=self.request_chat.is_username + has_username=self.request_chat.is_username, + user_admin_rights=user_admin_rights, + bot_admin_rights=bot_admin_rights ), max_quantity=self.request_chat.max, name_requested=self.request_chat.is_name_requested, @@ -155,7 +202,9 @@ class KeyboardButton(Object): creator=self.request_chat.is_creator, bot_participant=self.request_chat.is_bot_participant, has_username=self.request_chat.is_username, - forum=self.request_chat.is_forum + forum=self.request_chat.is_forum, + user_admin_rights=user_admin_rights, + bot_admin_rights=bot_admin_rights ), max_quantity=self.request_chat.max, name_requested=self.request_chat.is_name_requested, diff --git a/pyrogram/types/bots_and_keyboards/request_peer_type_channel.py b/pyrogram/types/bots_and_keyboards/request_peer_type_channel.py index c7283ee7..d21e77a0 100644 --- a/pyrogram/types/bots_and_keyboards/request_peer_type_channel.py +++ b/pyrogram/types/bots_and_keyboards/request_peer_type_channel.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrofork. If not, see . +from pyrogram import types + from ..object import Object @@ -47,17 +49,25 @@ class RequestPeerTypeChannel(Object): is_photo_requested (``bool``, *optional*): If True, Channel photo is requested. default True. + + user_privileges (:obj:`~pyrogram.types.ChatPrivileges`, *optional*): + Privileged actions that an user administrator is able to take. + + bot_privileges (:obj:`~pyrogram.types.ChatPrivileges`, *optional*): + Privileged actions that a bot administrator is able to take. """ # TODO user_admin_rights, bot_admin_rights def __init__( self, - button_id: int=0, - is_creator: bool=None, - is_username: bool=None, - max: int=1, - is_name_requested: bool=True, - is_username_requested: bool=True, - is_photo_requested: bool=True + button_id: int = 0, + is_creator: bool = None, + is_username: bool = None, + max: int = 1, + is_name_requested: bool = True, + is_username_requested: bool = True, + is_photo_requested: bool = True, + user_privileges: "types.ChatPrivileges" = None, + bot_privileges: "types.ChatPrivileges" = None ): super().__init__() @@ -68,3 +78,6 @@ class RequestPeerTypeChannel(Object): self.is_name_requested = is_name_requested self.is_username_requested = is_username_requested self.is_photo_requested = is_photo_requested + self.user_privileges = user_privileges + self.bot_privileges = bot_privileges + diff --git a/pyrogram/types/bots_and_keyboards/request_peer_type_chat.py b/pyrogram/types/bots_and_keyboards/request_peer_type_chat.py index 59d87300..cc800e4f 100644 --- a/pyrogram/types/bots_and_keyboards/request_peer_type_chat.py +++ b/pyrogram/types/bots_and_keyboards/request_peer_type_chat.py @@ -16,6 +16,8 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrofork. If not, see . +from pyrogram import types + from ..object import Object @@ -53,19 +55,27 @@ class RequestPeerTypeChat(Object): is_photo_requested (``bool``, *optional*): If True, Chat photo is requested. default True. + + user_privileges (:obj:`~pyrogram.types.ChatPrivileges`, *optional*): + Privileged actions that an user administrator is able to take. + + bot_privileges (:obj:`~pyrogram.types.ChatPrivileges`, *optional*): + Privileged actions that a bot administrator is able to take. """ # TODO user_admin_rights, bot_admin_rights def __init__( self, - button_id: int=0, - is_creator: bool=None, - is_bot_participant: bool=None, - is_username: bool=None, - is_forum: bool=None, - max: int=1, - is_name_requested: bool=True, - is_username_requested: bool=True, - is_photo_requested: bool=True + button_id: int = 0, + is_creator: bool = None, + is_bot_participant: bool = None, + is_username: bool = None, + is_forum: bool = None, + max: int = 1, + is_name_requested: bool = True, + is_username_requested: bool = True, + is_photo_requested: bool = True, + user_privileges: "types.ChatPrivileges" = None, + bot_privileges: "types.ChatPrivileges" = None ): super().__init__() @@ -78,3 +88,5 @@ class RequestPeerTypeChat(Object): self.is_name_requested = is_name_requested self.is_username_requested = is_username_requested self.is_photo_requested = is_photo_requested + self.user_privileges = user_privileges + self.bot_privileges = bot_privileges From 390786d92ca0827d0318ae2af08afc3ff6f3fce7 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 20:56:05 +0700 Subject: [PATCH 08/39] pyrofork: Add new ChatType (MONOFORUM) Signed-off-by: wulan17 --- pyrogram/enums/chat_type.py | 3 +++ pyrogram/types/user_and_chats/chat.py | 10 +++++++++- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/pyrogram/enums/chat_type.py b/pyrogram/enums/chat_type.py index 47d14f71..1b6ebe3c 100644 --- a/pyrogram/enums/chat_type.py +++ b/pyrogram/enums/chat_type.py @@ -39,3 +39,6 @@ class ChatType(AutoName): CHANNEL = auto() "Chat is a channel" + + MONOFORUM = auto() + "Chat is a monoforum" diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 64acdb37..5395dc8b 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -394,6 +394,14 @@ class Chat(Object): restriction_reason = getattr(channel, "restriction_reason", []) user_name = getattr(channel, "username", None) active_usernames = getattr(channel, "usernames", []) + if getattr(channel, "monoforum", None): + chat_type = enums.ChatType.MONOFORUM + elif getattr(channel, "megagroup", None): + chat_type = enums.ChatType.SUPERGROUP + elif getattr(channel, "broadcast", None): + chat_type = enums.ChatType.CHANNEL + else: + chat_type = enums.ChatType.GROUP usernames = None if len(active_usernames) >= 1: usernames = [] @@ -410,7 +418,7 @@ class Chat(Object): return Chat( id=peer_id, - type=enums.ChatType.SUPERGROUP if getattr(channel, "megagroup", None) else enums.ChatType.CHANNEL, + type=chat_type, is_verified=getattr(channel, "verified", None), is_restricted=getattr(channel, "restricted", None), is_creator=getattr(channel, "creator", None), From ffec107a2c1bd6cee7299a4a1faf5d89bddfb152 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 21:02:30 +0700 Subject: [PATCH 09/39] pyrofork: Drop Chat.is_forum and add new ChatType (FORUM) Signed-off-by: wulan17 --- pyrogram/enums/chat_type.py | 3 +++ pyrogram/types/bots_and_keyboards/keyboard_button.py | 2 +- pyrogram/types/messages_and_media/message.py | 4 ++-- pyrogram/types/user_and_chats/chat.py | 8 ++------ 4 files changed, 8 insertions(+), 9 deletions(-) diff --git a/pyrogram/enums/chat_type.py b/pyrogram/enums/chat_type.py index 1b6ebe3c..10cf8db6 100644 --- a/pyrogram/enums/chat_type.py +++ b/pyrogram/enums/chat_type.py @@ -40,5 +40,8 @@ class ChatType(AutoName): CHANNEL = auto() "Chat is a channel" + FORUM = auto() + "Chat is a forum" + MONOFORUM = auto() "Chat is a monoforum" diff --git a/pyrogram/types/bots_and_keyboards/keyboard_button.py b/pyrogram/types/bots_and_keyboards/keyboard_button.py index f565a64a..9d722310 100644 --- a/pyrogram/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/keyboard_button.py @@ -17,7 +17,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrofork. If not, see . -from pyrogram import raw, types +from pyrogram import enums, raw, types from ..object import Object from typing import Union diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index e91d915c..7769ec23 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -970,7 +970,7 @@ class Message(Object, Update): else: parsed_message.message_thread_id = message.reply_to.reply_to_msg_id parsed_message.is_topic_message = True - elif parsed_message.chat.is_forum and parsed_message.message_thread_id is None: + elif parsed_message.chat.type == enums.ChatType.FORUM and parsed_message.message_thread_id is None: parsed_message.message_thread_id = 1 parsed_message.is_topic_message = True @@ -1299,7 +1299,7 @@ class Message(Object, Update): pass else: parsed_message.reply_to_story = reply_to_story - if parsed_message.chat.is_forum and parsed_message.message_thread_id is None: + if parsed_message.chat.type == enums.ChatType.FORUM and parsed_message.message_thread_id is None: parsed_message.message_thread_id = 1 parsed_message.is_topic_message = True diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 5395dc8b..163f5d83 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -56,9 +56,6 @@ class Chat(Object): is_support (``bool``): True, if this chat is part of the Telegram support team. Users and bots only. - is_forum (``bool``, *optional*): - True, if the supergroup chat is a forum - is_participants_hidden (``bool``, *optional*): True, if the chat members are hidden. Returned only in :meth:`~pyrogram.Client.get_chat`. @@ -231,7 +228,6 @@ class Chat(Object): is_scam: bool = None, is_fake: bool = None, is_support: bool = None, - is_forum: bool = None, is_participants_hidden: bool = None, is_join_request: bool = None, is_join_to_send: bool = None, @@ -286,7 +282,6 @@ class Chat(Object): self.is_scam = is_scam self.is_fake = is_fake self.is_support = is_support - self.is_forum = is_forum self.is_participants_hidden = is_participants_hidden self.is_join_request = is_join_request self.is_join_to_send = is_join_to_send @@ -396,6 +391,8 @@ class Chat(Object): active_usernames = getattr(channel, "usernames", []) if getattr(channel, "monoforum", None): chat_type = enums.ChatType.MONOFORUM + elif getattr(channel, "forum", None): + chat_type = enums.ChatType.FORUM elif getattr(channel, "megagroup", None): chat_type = enums.ChatType.SUPERGROUP elif getattr(channel, "broadcast", None): @@ -424,7 +421,6 @@ class Chat(Object): is_creator=getattr(channel, "creator", None), is_scam=getattr(channel, "scam", None), is_fake=getattr(channel, "fake", None), - is_forum=getattr(channel, "forum", None), is_join_request=getattr(channel, "join_request", None), is_join_to_send=getattr(channel, "join_to_send", None), is_slowmode_enabled=getattr(channel, "slowmode_enabled", None), From c0dcac1fde4740ff44f2e03f8f8abb65c8d05edf Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 21:07:46 +0700 Subject: [PATCH 10/39] pyrofork: Add linked_forum field to Chat Signed-off-by: wulan17 --- pyrogram/types/user_and_chats/chat.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index 163f5d83..cd42e983 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -167,6 +167,10 @@ class Chat(Object): The linked discussion group (in case of channels) or the linked channel (in case of supergroups). Returned only in :meth:`~pyrogram.Client.get_chat`. + linked_forum (:obj:`~pyrogram.types.Chat`, *optional*): + The linked monoforum (in case of channels) or the linked channel (in case of monoforum). + Returned only in :meth:`~pyrogram.Client.get_chat`. + send_as_chat (:obj:`~pyrogram.types.Chat`, *optional*): The default "send_as" chat. Returned only in :meth:`~pyrogram.Client.get_chat`. @@ -259,6 +263,7 @@ class Chat(Object): permissions: "types.ChatPermissions" = None, distance: int = None, linked_chat: "types.Chat" = None, + linked_forum: "types.Chat" = None, send_as_chat: "types.Chat" = None, available_reactions: Optional["types.ChatReactions"] = None, usernames: List["types.Username"] = None, @@ -313,6 +318,7 @@ class Chat(Object): self.permissions = permissions self.distance = distance self.linked_chat = linked_chat + self.linked_forum = linked_forum self.send_as_chat = send_as_chat self.available_reactions = available_reactions self.usernames = usernames @@ -550,9 +556,14 @@ class Chat(Object): linked_chat_raw = chats.get(full_chat.linked_chat_id, None) + linked_forum_raw = chats.get(getattr(chat_raw, "linked_monoforum_id"), None) + if linked_chat_raw: parsed_chat.linked_chat = Chat._parse_channel_chat(client, linked_chat_raw) + if linked_forum_raw: + parsed_chat.linked_forum = Chat._parse_channel_chat(client, linked_forum_raw) + default_send_as = full_chat.default_send_as if default_send_as: From 068181682eae4e769ec26c612364afdbfd340544 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 22:26:27 +0700 Subject: [PATCH 11/39] pyrofork: Add ALLOW_PAYMENT_REQUIRED_X exception Signed-off-by: wulan17 --- compiler/errors/source/403_FORBIDDEN.tsv | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/errors/source/403_FORBIDDEN.tsv b/compiler/errors/source/403_FORBIDDEN.tsv index 44a76324..452ea59c 100644 --- a/compiler/errors/source/403_FORBIDDEN.tsv +++ b/compiler/errors/source/403_FORBIDDEN.tsv @@ -44,3 +44,4 @@ GROUPCALL_ALREADY_STARTED The groupcall has already started, you can join direct GROUPCALL_FORBIDDEN The group call has already ended LIVE_DISABLED Story is disabled server-side CHAT_GUEST_SEND_FORBIDDEN You need to join the discussion group before commenting +ALLOW_PAYMENT_REQUIRED_X Payment of {value} stars is required to perform this action \ No newline at end of file From 1ed7add4ddac3d6b6bfec9d4f549c2670dbf19cb Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 22:36:11 +0700 Subject: [PATCH 12/39] pyrofork: Add paid_message_price_changed field to Message Signed-off-by: wulan17 --- compiler/docs/compiler.py | 1 + pyrogram/enums/message_service_type.py | 3 ++ pyrogram/types/messages_and_media/message.py | 7 +++ pyrogram/types/payments/__init__.py | 2 + .../payments/paid_message_price_changed.py | 49 +++++++++++++++++++ 5 files changed, 62 insertions(+) create mode 100644 pyrogram/types/payments/paid_message_price_changed.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 3a9e913c..126dba9e 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -609,6 +609,7 @@ def pyrogram_api(): Invoice LabeledPrice PaidMedia + PaidMessagePriceChanged PaymentForm PaymentInfo PaymentRefunded diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index a2fbc90a..5f25dd6b 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -132,3 +132,6 @@ class MessageServiceType(AutoName): SCREENSHOT_TAKEN = auto() "Screenshot taken" + + PAID_MESSAGE_PRICE_CHANGED = auto() + "Paid message price changed" diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index 7769ec23..bb6007c2 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -480,6 +480,7 @@ class Message(Object, Update): gift_code: "types.GiftCode" = None, gift: "types.Gift" = None, screenshot_taken: "types.ScreenshotTaken" = None, + paid_message_price_changed: "types.PaidMessagePriceChanged" = None, invoice: "types.Invoice" = None, story: Union["types.MessageStory", "types.Story"] = None, alternative_videos: List["types.AlternativeVideo"] = None, @@ -596,6 +597,7 @@ class Message(Object, Update): self.gift_code = gift_code self.gift = gift self.screenshot_taken = screenshot_taken + self.paid_message_price_changed = paid_message_price_changed self.invoice = invoice self.story = story self.video = video @@ -760,6 +762,7 @@ class Message(Object, Update): gift_code = None gift = None screenshot_taken = None + paid_message_price_changed = None service_type = None chat_join_type = None @@ -881,6 +884,9 @@ class Message(Object, Update): elif isinstance(action, raw.types.MessageActionScreenshotTaken): screenshot_taken = types.ScreenshotTaken() service_type = enums.MessageServiceType.SCREENSHOT_TAKEN + elif isinstance(action, raw.types.MessageActionPaidMessagesPrice): + paid_message_price_changed = types.PaidMessagePriceChanged._parse(action) + service_type = enums.MessageServiceType.PAID_MESSAGE_PRICE_CHANGED parsed_message = Message( id=message.id, @@ -926,6 +932,7 @@ class Message(Object, Update): contact_registered=contact_registered, gift_code=gift_code, screenshot_taken=screenshot_taken, + paid_message_price_changed=paid_message_price_changed, raw=message, chat_join_type=chat_join_type, client=client diff --git a/pyrogram/types/payments/__init__.py b/pyrogram/types/payments/__init__.py index 7dc9e6bd..dbb02e4e 100644 --- a/pyrogram/types/payments/__init__.py +++ b/pyrogram/types/payments/__init__.py @@ -27,6 +27,7 @@ from .input_stars_transaction import InputStarsTransaction from .invoice import Invoice from .labeled_price import LabeledPrice from .paid_media import PaidMedia +from .paid_message_price_changed import PaidMessagePriceChanged from .payment_form import PaymentForm from .payment_info import PaymentInfo from .payment_refunded import PaymentRefunded @@ -46,6 +47,7 @@ __all__ = [ "Invoice", "LabeledPrice", "PaidMedia", + "PaidMessagePriceChanged", "PaymentForm", "PaymentInfo", "PaymentRefunded", diff --git a/pyrogram/types/payments/paid_message_price_changed.py b/pyrogram/types/payments/paid_message_price_changed.py new file mode 100644 index 00000000..d248df2d --- /dev/null +++ b/pyrogram/types/payments/paid_message_price_changed.py @@ -0,0 +1,49 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +from typing import List, Union + +from pyrogram import raw +from pyrogram import types +from ..object import Object + + +class PaidMessagePriceChanged(Object): + """A PaidMessagePriceChanged. + + Parameters: + stars_amount (``int``): + Amount of stars. + + extended_media (List of :obj:`~pyrogram.types.Animation` | :obj:`~pyrogram.types.ExtendedMediaPreview` | :obj:`~pyrogram.types.Photo` | :obj:`~pyrogram.types.Video`, *optional*): + Extended media. + """ + def __init__( + self, + *, + stars_amount: int, + ): + super().__init__() + + self.stars_amount = stars_amount + + @staticmethod + def _parse(action: "raw.types.MessageActionPaidMessagesPrice") -> "PaidMessagePriceChanged": + return PaidMessagePriceChanged( + stars_amount=action.stars + ) From bd5603a6a7f1ac4da08a8431523e4b25658f3007 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 9 Jun 2025 22:44:59 +0700 Subject: [PATCH 13/39] pyrofork: Add STARS_AMOUNT_INVALID exception Signed-off-by: wulan17 --- compiler/errors/source/400_BAD_REQUEST.tsv | 1 + 1 file changed, 1 insertion(+) diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 2d75f9cb..2212ec2d 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -503,3 +503,4 @@ BOOSTS_EMPTY You can't modify the icon of the General topic. BOOST_NOT_MODIFIED You're already boosting the specified channel. PAYMENT_REQUIRED The payment is required BOOST_PEER_INVALID The specified `boost_peer` is invalid. +STARS_AMOUNT_INVALID The specified `amount` is invalid. \ No newline at end of file From a2f3a6a27b36fd5fa4356a52dd556822ccb745f2 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Tue, 10 Jun 2025 20:06:56 +0700 Subject: [PATCH 14/39] pyrofork: Add reply_to_monoforum_id parameter to supported send_* Signed-off-by: wulan17 --- compiler/docs/compiler.py | 1 + pyrogram/methods/messages/send_animation.py | 7 +++ pyrogram/methods/messages/send_audio.py | 7 +++ .../methods/messages/send_cached_media.py | 7 +++ pyrogram/methods/messages/send_contact.py | 7 +++ pyrogram/methods/messages/send_dice.py | 7 +++ pyrogram/methods/messages/send_document.py | 7 +++ pyrogram/methods/messages/send_location.py | 7 +++ pyrogram/methods/messages/send_media_group.py | 7 +++ pyrogram/methods/messages/send_message.py | 7 +++ pyrogram/methods/messages/send_photo.py | 7 +++ pyrogram/methods/messages/send_sticker.py | 7 +++ pyrogram/methods/messages/send_video.py | 7 +++ pyrogram/methods/messages/send_video_note.py | 7 +++ pyrogram/methods/messages/send_voice.py | 7 +++ pyrogram/methods/messages/send_web_page.py | 7 +++ .../types/input_message_content/__init__.py | 2 + .../input_reply_to_monoforum.py | 43 +++++++++++++++++++ pyrogram/utils.py | 10 ++++- 19 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 pyrogram/types/input_message_content/input_reply_to_monoforum.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 126dba9e..c2cec445 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -719,6 +719,7 @@ def pyrogram_api(): InputMessageContent InputMessageContent InputReplyToMessage + InputReplyToMonoforum InputReplyToStory InputTextMessageContent InputLocationMessageContent diff --git a/pyrogram/methods/messages/send_animation.py b/pyrogram/methods/messages/send_animation.py index 99c67749..f77244cd 100644 --- a/pyrogram/methods/messages/send_animation.py +++ b/pyrogram/methods/messages/send_animation.py @@ -52,6 +52,7 @@ class SendAnimation: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -145,6 +146,11 @@ class SendAnimation: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -226,6 +232,7 @@ class SendAnimation: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_audio.py b/pyrogram/methods/messages/send_audio.py index 967958e0..752dee58 100644 --- a/pyrogram/methods/messages/send_audio.py +++ b/pyrogram/methods/messages/send_audio.py @@ -50,6 +50,7 @@ class SendAudio: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, message_effect_id: int = None, @@ -137,6 +138,11 @@ class SendAudio: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -216,6 +222,7 @@ class SendAudio: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_cached_media.py b/pyrogram/methods/messages/send_cached_media.py index 8fc8071c..05875f52 100644 --- a/pyrogram/methods/messages/send_cached_media.py +++ b/pyrogram/methods/messages/send_cached_media.py @@ -40,6 +40,7 @@ class SendCachedMedia: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -104,6 +105,11 @@ class SendCachedMedia: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -144,6 +150,7 @@ class SendCachedMedia: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_contact.py b/pyrogram/methods/messages/send_contact.py index c50d03bd..bd96d7ef 100644 --- a/pyrogram/methods/messages/send_contact.py +++ b/pyrogram/methods/messages/send_contact.py @@ -38,6 +38,7 @@ class SendContact: business_connection_id: str = None, reply_to_message_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -95,6 +96,11 @@ class SendContact: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -139,6 +145,7 @@ class SendContact: reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_dice.py b/pyrogram/methods/messages/send_dice.py index d96025ed..0cd63a11 100644 --- a/pyrogram/methods/messages/send_dice.py +++ b/pyrogram/methods/messages/send_dice.py @@ -36,6 +36,7 @@ class SendDice: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -91,6 +92,11 @@ class SendDice: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -143,6 +149,7 @@ class SendDice: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_document.py b/pyrogram/methods/messages/send_document.py index cc29985e..efb1da72 100644 --- a/pyrogram/methods/messages/send_document.py +++ b/pyrogram/methods/messages/send_document.py @@ -48,6 +48,7 @@ class SendDocument: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, message_effect_id: int = None, @@ -129,6 +130,11 @@ class SendDocument: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -203,6 +209,7 @@ class SendDocument: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_location.py b/pyrogram/methods/messages/send_location.py index c8621a7d..0138f2a6 100644 --- a/pyrogram/methods/messages/send_location.py +++ b/pyrogram/methods/messages/send_location.py @@ -38,6 +38,7 @@ class SendLocation: business_connection_id: str = None, reply_to_message_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -89,6 +90,11 @@ class SendLocation: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + reply_to_message_id (``int``, *optional*): If the message is a reply, ID of the original message @@ -136,6 +142,7 @@ class SendLocation: reply_to_message_id=reply_to_message_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_media_group.py b/pyrogram/methods/messages/send_media_group.py index a6a14021..89867f0b 100644 --- a/pyrogram/methods/messages/send_media_group.py +++ b/pyrogram/methods/messages/send_media_group.py @@ -56,6 +56,7 @@ class SendMediaGroup: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -104,6 +105,11 @@ class SendMediaGroup: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -180,6 +186,7 @@ class SendMediaGroup: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode, diff --git a/pyrogram/methods/messages/send_message.py b/pyrogram/methods/messages/send_message.py index c8547f30..dd12e323 100644 --- a/pyrogram/methods/messages/send_message.py +++ b/pyrogram/methods/messages/send_message.py @@ -39,6 +39,7 @@ class SendMessage: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: int = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -100,6 +101,11 @@ class SendMessage: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of the monoforum. + for reply to message from a monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -174,6 +180,7 @@ class SendMessage: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_photo.py b/pyrogram/methods/messages/send_photo.py index 711d893d..be48619a 100644 --- a/pyrogram/methods/messages/send_photo.py +++ b/pyrogram/methods/messages/send_photo.py @@ -46,6 +46,7 @@ class SendPhoto: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -122,6 +123,11 @@ class SendPhoto: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -203,6 +209,7 @@ class SendPhoto: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_sticker.py b/pyrogram/methods/messages/send_sticker.py index f3e60cd2..7af70846 100644 --- a/pyrogram/methods/messages/send_sticker.py +++ b/pyrogram/methods/messages/send_sticker.py @@ -44,6 +44,7 @@ class SendSticker: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -104,6 +105,11 @@ class SendSticker: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -178,6 +184,7 @@ class SendSticker: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_video.py b/pyrogram/methods/messages/send_video.py index 5689dc5a..0702f34d 100644 --- a/pyrogram/methods/messages/send_video.py +++ b/pyrogram/methods/messages/send_video.py @@ -50,6 +50,7 @@ class SendVideo: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, cover: Union[str, BinaryIO] = None, @@ -151,6 +152,11 @@ class SendVideo: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -251,6 +257,7 @@ class SendVideo: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_video_note.py b/pyrogram/methods/messages/send_video_note.py index aa0a8def..bea7380e 100644 --- a/pyrogram/methods/messages/send_video_note.py +++ b/pyrogram/methods/messages/send_video_note.py @@ -45,6 +45,7 @@ class SendVideoNote: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, parse_mode: Optional["enums.ParseMode"] = None, @@ -118,6 +119,11 @@ class SendVideoNote: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -197,6 +203,7 @@ class SendVideoNote: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_voice.py b/pyrogram/methods/messages/send_voice.py index 2bcbb0ca..1ec3751b 100644 --- a/pyrogram/methods/messages/send_voice.py +++ b/pyrogram/methods/messages/send_voice.py @@ -46,6 +46,7 @@ class SendVoice: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -121,6 +122,11 @@ class SendVoice: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -189,6 +195,7 @@ class SendVoice: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/methods/messages/send_web_page.py b/pyrogram/methods/messages/send_web_page.py index be79610e..257b7bd7 100644 --- a/pyrogram/methods/messages/send_web_page.py +++ b/pyrogram/methods/messages/send_web_page.py @@ -39,6 +39,7 @@ class SendWebPage: reply_to_message_id: int = None, reply_to_story_id: int = None, reply_to_chat_id: Union[int, str] = None, + reply_to_monoforum_id: Union[int, str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, schedule_date: datetime = None, @@ -106,6 +107,11 @@ class SendWebPage: for reply to message from another chat. You can also use chat public link in form of *t.me/* (str). + reply_to_monoforum_id (``int`` | ``str``, *optional*): + Unique identifier for the target user of monoforum. + for reply to message from monoforum. + for channel administrators only. + quote_text (``str``, *optional*): Text to quote. for reply_to_message only. @@ -161,6 +167,7 @@ class SendWebPage: reply_to_story_id=reply_to_story_id, message_thread_id=message_thread_id, reply_to_chat_id=reply_to_chat_id, + reply_to_monoforum_id=reply_to_monoforum_id, quote_text=quote_text, quote_entities=quote_entities, parse_mode=parse_mode diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index 1a271da1..ae897b0d 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -19,6 +19,7 @@ from .input_message_content import InputMessageContent from .input_reply_to_message import InputReplyToMessage +from .input_reply_to_monoforum import InputReplyToMonoforum from .input_reply_to_story import InputReplyToStory from .input_text_message_content import InputTextMessageContent from .input_location_message_content import InputLocationMessageContent @@ -29,6 +30,7 @@ from .input_invoice_message_content import InputInvoiceMessageContent __all__ = [ "InputMessageContent", "InputReplyToMessage", + "InputReplyToMonoforum", "InputReplyToStory", "InputTextMessageContent", "InputLocationMessageContent", diff --git a/pyrogram/types/input_message_content/input_reply_to_monoforum.py b/pyrogram/types/input_message_content/input_reply_to_monoforum.py new file mode 100644 index 00000000..701e2900 --- /dev/null +++ b/pyrogram/types/input_message_content/input_reply_to_monoforum.py @@ -0,0 +1,43 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +from pyrogram import raw +from ..object import Object + + +class InputReplyToMonoforum(Object): + """Contains information about a target replied monoforum. + + + Parameters: + monoforum_peer (:obj:`~pyrogram.raw.types.InputPeer`): + An InputPeer. + """ + + def __init__( + self, *, + monoforum_peer: "raw.types.InputPeer" + ): + super().__init__() + + self.monoforum_peer = monoforum_peer + + def write(self): + return raw.types.InputReplyToMonoForum( + monoforum_peer_id=self.monoforum_peer + ).write() diff --git a/pyrogram/utils.py b/pyrogram/utils.py index 4ad6c5c2..fc0e9abd 100644 --- a/pyrogram/utils.py +++ b/pyrogram/utils.py @@ -487,6 +487,7 @@ async def get_reply_to( reply_to_message_id: int = None, reply_to_story_id: int = None, message_thread_id: int = None, + reply_to_monoforum_id: Union[int,str] = None, reply_to_chat_id: Union[int,str] = None, quote_text: str = None, quote_entities: List["types.MessageEntity"] = None, @@ -495,7 +496,12 @@ async def get_reply_to( ): reply_to = None reply_to_chat = None - if reply_to_message_id or message_thread_id: + if reply_to_monoforum_id: + peer = await client.resolve_peer(reply_to_monoforum_id) + reply_to = types.InputReplyToMonoforum( + monoforum_peer=peer + ) + elif reply_to_message_id or message_thread_id: text, entities = (await parse_text_entities(client, quote_text, parse_mode, quote_entities)).values() if reply_to_chat_id is not None: reply_to_chat = await client.resolve_peer(reply_to_chat_id) @@ -507,7 +513,7 @@ async def get_reply_to( quote_entities=entities, quote_offset=quote_offset, ) - if reply_to_story_id: + elif reply_to_story_id: peer = await client.resolve_peer(chat_id) reply_to = types.InputReplyToStory( peer=peer, From b6c615df7a6c7e408bb9fab88731ba4408aadec3 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Thu, 1 May 2025 01:16:11 +0300 Subject: [PATCH 15/39] Add get_business_account_gifts and get_business_account_star_balance method Signed-off-by: wulan17 --- compiler/docs/compiler.py | 2 + pyrogram/methods/business/__init__.py | 4 + .../business/get_business_account_gifts.py | 129 ++++++++++++++++++ .../get_business_account_star_balance.py | 61 +++++++++ 4 files changed, 196 insertions(+) create mode 100644 pyrogram/methods/business/get_business_account_gifts.py create mode 100644 pyrogram/methods/business/get_business_account_star_balance.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index c2cec445..daff224f 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -415,6 +415,8 @@ def pyrogram_api(): answer_shipping_query delete_business_messages get_business_connection + get_business_account_gifts + get_business_account_star_balance """, authorization=""" Authorization diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index 2bf6fd21..02123860 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -21,6 +21,8 @@ from .answer_pre_checkout_query import AnswerPreCheckoutQuery from .answer_shipping_query import AnswerShippingQuery from .delete_business_messages import DeleteBusinessMessages from .get_business_connection import GetBusinessConnection +from .get_business_account_gifts import GetBusinessAccountGifts +from .get_business_account_star_balance import GetBusinessAccountStarBalance class TelegramBusiness( @@ -28,5 +30,7 @@ class TelegramBusiness( AnswerShippingQuery, DeleteBusinessMessages, GetBusinessConnection, + GetBusinessAccountGifts, + GetBusinessAccountStarBalance ): pass diff --git a/pyrogram/methods/business/get_business_account_gifts.py b/pyrogram/methods/business/get_business_account_gifts.py new file mode 100644 index 00000000..44f08898 --- /dev/null +++ b/pyrogram/methods/business/get_business_account_gifts.py @@ -0,0 +1,129 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Optional + +import pyrogram +from pyrogram import raw, types + + +class GetBusinessAccountGifts: + async def get_business_account_gifts( + self: "pyrogram.Client", + business_connection_id: str, + exclude_unsaved: Optional[bool] = None, + exclude_saved: Optional[bool] = None, + exclude_unlimited: Optional[bool] = None, + exclude_limited: Optional[bool] = None, + exclude_upgraded: Optional[bool] = None, + sort_by_price: Optional[bool] = None, + limit: int = 0, + offset: str = "", + ): + """Return the gifts received and owned by a managed business account. + + .. note:: + + Requires the `can_view_gifts_and_stars` business bot right. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + business_connection_id (``str``): + Unique identifier of business connection on behalf of which to send the request. + + exclude_unsaved (``bool``, *optional*): + Pass True to exclude gifts that aren’t saved to the account’s profile page. + + exclude_saved (``bool``, *optional*): + Pass True to exclude gifts that are saved to the account’s profile page. + + exclude_unlimited (``bool``, *optional*): + Pass True to exclude gifts that can be purchased an unlimited number of times. + + exclude_limited (``bool``, *optional*): + Pass True to exclude gifts that can be purchased a limited number of times. + + exclude_upgraded (``bool``, *optional*): + Pass True to exclude upgraded gifts. + + sort_by_price (``bool``, *optional*): + Pass True to sort results by gift price instead of send date. Sorting is applied before pagination. + + offset (``str``, *optional*): + Offset of the first entry to return as received from the previous request. + + limit (``int``, *optional*): + The maximum number of gifts to be returned. + + Returns: + ``Generator``: A generator yielding :obj:`~pyrogram.types.Gift` objects. + + Example: + .. code-block:: python + + async for gift in app.get_business_account_gifts(connection_id): + print(gift) + """ + current = 0 + total = abs(limit) or (1 << 31) - 1 + limit = min(100, total) + + connection_info = await self.get_business_connection(business_connection_id) + + while True: + r = await self.invoke( + raw.functions.payments.GetSavedStarGifts( + peer=await self.resolve_peer(connection_info.user.id), + offset=offset, + limit=limit, + exclude_unsaved=exclude_unsaved, + exclude_saved=exclude_saved, + exclude_unlimited=exclude_unlimited, + exclude_limited=exclude_limited, + exclude_unique=exclude_upgraded, + sort_by_value=sort_by_price + ), + sleep_threshold=60, + business_connection_id=business_connection_id + ) + + users = {i.id: i for i in r.users} + chats = {i.id: i for i in r.chats} + + user_star_gifts = [ + await types.Gift._parse_saved(self, gift, users, chats) + for gift in r.gifts + ] + + if not user_star_gifts: + return + + for gift in user_star_gifts: + yield gift + + current += 1 + + if current >= total: + return + + offset = r.next_offset + + if not offset: + return diff --git a/pyrogram/methods/business/get_business_account_star_balance.py b/pyrogram/methods/business/get_business_account_star_balance.py new file mode 100644 index 00000000..90a81b5f --- /dev/null +++ b/pyrogram/methods/business/get_business_account_star_balance.py @@ -0,0 +1,61 @@ +# Pyrogram - Telegram MTProto API Client Library for Python +# Copyright (C) 2017-present Dan +# Copyright (C) 2022-present Mayuri-Chan +# +# This file is part of Pyrogram. +# +# Pyrogram is free software: you can redistribute it and/or modify +# it under the terms of the GNU Lesser General Public License as published +# by the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Pyrogram is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public License +# along with Pyrogram. If not, see . + +from typing import Optional, Union + +import pyrogram +from pyrogram import raw + + +class GetBusinessAccountStarBalance: + async def get_business_account_star_balance( + self: "pyrogram.Client", + business_connection_id: str, + ) -> int: + """Return the amount of Telegram Stars owned by a managed business account. + + .. note:: + + Requires the `can_view_gifts_and_stars` business bot right. + + .. include:: /_includes/usable-by/bots.rst + + Parameters: + business_connection_id (``str``): + Unique identifier of business connection on behalf of which to send the request. + + Returns: + ``int``: On success, the current stars balance is returned. + + Example: + .. code-block:: python + + # Get stars balance + await app.get_business_account_star_balance("connection_id") + """ + connection_info = await self.get_business_connection(business_connection_id) + + r = await self.invoke( + raw.functions.payments.GetStarsStatus( + peer=await self.resolve_peer(connection_info.user.id), + ), + business_connection_id=business_connection_id + ) + + return r.balance.amount From a1e3f0f5db988cd0fa0326824cb61128902bc812 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Fri, 23 May 2025 12:44:14 +0300 Subject: [PATCH 16/39] Add transfer_business_account_stars method Signed-off-by: wulan17 --- compiler/docs/compiler.py | 1 + compiler/errors/source/400_BAD_REQUEST.tsv | 2 + pyrogram/methods/business/__init__.py | 4 +- .../transfer_business_account_stars.py | 72 +++++++++++++++++++ 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 pyrogram/methods/business/transfer_business_account_stars.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index daff224f..5c198847 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -417,6 +417,7 @@ def pyrogram_api(): get_business_connection get_business_account_gifts get_business_account_star_balance + transfer_business_account_stars """, authorization=""" Authorization diff --git a/compiler/errors/source/400_BAD_REQUEST.tsv b/compiler/errors/source/400_BAD_REQUEST.tsv index 2212ec2d..ee599c5f 100644 --- a/compiler/errors/source/400_BAD_REQUEST.tsv +++ b/compiler/errors/source/400_BAD_REQUEST.tsv @@ -35,6 +35,7 @@ BOT_GAMES_DISABLED Bot games cannot be used in this type of chat BOT_GROUPS_BLOCKED This bot can't be added to groups BOT_INLINE_DISABLED The inline feature of the bot is disabled BOT_INVALID This is not a valid bot +BOT_INVOICE_INVALID The provided invoice is invalid BOT_METHOD_INVALID The method can't be used by bots BOT_MISSING This method can only be run by a bot BOT_ONESIDE_NOT_AVAIL Bots can't pin messages for one side only in private chats @@ -46,6 +47,7 @@ BROADCAST_CALLS_DISABLED Broadcast calls disabled BROADCAST_ID_INVALID The channel is invalid BROADCAST_PUBLIC_VOTERS_FORBIDDEN Polls with public voters cannot be sent in channels BROADCAST_REQUIRED The request can only be used with a channel +BUSINESS_BOT_MISSING Business bot missing BUTTON_DATA_INVALID The button callback data is invalid or too large BUTTON_ID_INVALID The button_id parameter is invalid BUTTON_TEXT_INVALID The specified button text is invalid diff --git a/pyrogram/methods/business/__init__.py b/pyrogram/methods/business/__init__.py index 02123860..cac6b40d 100644 --- a/pyrogram/methods/business/__init__.py +++ b/pyrogram/methods/business/__init__.py @@ -23,6 +23,7 @@ from .delete_business_messages import DeleteBusinessMessages from .get_business_connection import GetBusinessConnection from .get_business_account_gifts import GetBusinessAccountGifts from .get_business_account_star_balance import GetBusinessAccountStarBalance +from .transfer_business_account_stars import TransferBusinessAccountStars class TelegramBusiness( @@ -31,6 +32,7 @@ class TelegramBusiness( DeleteBusinessMessages, GetBusinessConnection, GetBusinessAccountGifts, - GetBusinessAccountStarBalance + GetBusinessAccountStarBalance, + TransferBusinessAccountStars, ): pass diff --git a/pyrogram/methods/business/transfer_business_account_stars.py b/pyrogram/methods/business/transfer_business_account_stars.py new file mode 100644 index 00000000..fbbdc2d0 --- /dev/null +++ b/pyrogram/methods/business/transfer_business_account_stars.py @@ -0,0 +1,72 @@ +# 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 . + +import pyrogram +from pyrogram import raw + + +class TransferBusinessAccountStars: + async def transfer_business_account_stars( + self: "pyrogram.Client", + business_connection_id: str, + star_count: int, + ) -> bool: + """Transfers Telegram Stars from the business account balance to the bot’s balance. + + .. note:: + + Requires the `can_transfer_stars` business bot right. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + business_connection_id (``str``): + Unique identifier of the business connection. + + star_count (``int`` | ``str``): + Number of Telegram Stars to transfer, 1-10000. + + Returns: + ``bool``: On success, True is returned. + """ + # Why telegram won't let us just use InputPeerSelf :( + if self.me: + bot_id = self.me.id + else: + bot_id = ( + await self.invoke(raw.functions.users.GetUsers(id=[raw.types.InputPeerSelf()])) + )[0].id + + invoice = raw.types.InputInvoiceBusinessBotTransferStars( + bot=await self.resolve_peer(bot_id), stars=star_count + ) + + payment_form = await self.invoke( + raw.functions.payments.GetPaymentForm(invoice=invoice), + business_connection_id=business_connection_id, + ) + + await self.invoke( + raw.functions.payments.SendStarsForm( + form_id=payment_form.form_id, + invoice=invoice, + ), + business_connection_id=business_connection_id, + ) + + return True From e5b5ef5072e0780974dde6a05cf267960863d689 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Tue, 10 Jun 2025 22:38:59 +0700 Subject: [PATCH 17/39] pyrofork: Bump version to 2.3.65 Signed-off-by: wulan17 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 49a2aeb9..49dc7c26 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -18,7 +18,7 @@ # along with Pyrofork. If not, see . __fork_name__ = "PyroFork" -__version__ = "2.3.64" +__version__ = "2.3.65" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2022-present Mayuri-Chan " From e33d0bde656c30b45106e5aae74334f45803928a Mon Sep 17 00:00:00 2001 From: wulan17 Date: Tue, 10 Jun 2025 22:44:31 +0700 Subject: [PATCH 18/39] pyrofork: fix typo Signed-off-by: wulan17 --- compiler/docs/compiler.py | 2 +- pyrogram/methods/payments/__init__.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 5c198847..728a832c 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -373,7 +373,7 @@ def pyrogram_api(): send_gift send_resold_gift set_gift_resale_price - set_pinned_gift + set_pinned_gifts show_gift transfer_gift upgrade_gift diff --git a/pyrogram/methods/payments/__init__.py b/pyrogram/methods/payments/__init__.py index 5164f94c..b4185a50 100644 --- a/pyrogram/methods/payments/__init__.py +++ b/pyrogram/methods/payments/__init__.py @@ -39,7 +39,7 @@ from .send_payment_form import SendPaymentForm from .send_gift import SendGift from .send_resold_gift import SendResoldGift from .set_gift_resale_price import SetGiftResalePrice -from .set_pinned_gift import SetPinnedGift +from .set_pinned_gifts import SetPinnedGifts from .show_gift import ShowGift from .transfer_gift import TransferGift from .upgrade_gift import UpgradeGift @@ -67,7 +67,7 @@ class Payments( SendGift, SendResoldGift, SetGiftResalePrice, - SetPinnedGift, + SetPinnedGifts, ShowGift, TransferGift, UpgradeGift From 6f616ebed8f9bdb3d48a737af89973cf26f1d366 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Tue, 10 Jun 2025 22:48:38 +0700 Subject: [PATCH 19/39] pyrofork: Bump version to 2.3.66 Signed-off-by: wulan17 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 49dc7c26..36f5975d 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -18,7 +18,7 @@ # along with Pyrofork. If not, see . __fork_name__ = "PyroFork" -__version__ = "2.3.65" +__version__ = "2.3.66" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2022-present Mayuri-Chan " From 9ff40dc90b69ac825ccf9bf9c1a95aab7da0bf1c Mon Sep 17 00:00:00 2001 From: wulan17 Date: Sat, 21 Jun 2025 19:26:45 +0700 Subject: [PATCH 20/39] pyrofork: fix typo in KeyboardButton Signed-off-by: wulan17 --- pyrogram/types/bots_and_keyboards/keyboard_button.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/bots_and_keyboards/keyboard_button.py b/pyrogram/types/bots_and_keyboards/keyboard_button.py index 9d722310..82c30b87 100644 --- a/pyrogram/types/bots_and_keyboards/keyboard_button.py +++ b/pyrogram/types/bots_and_keyboards/keyboard_button.py @@ -143,8 +143,8 @@ class KeyboardButton(Object): elif self.request_location: return raw.types.KeyboardButtonRequestGeoLocation(text=self.text) elif self.request_chat: - user_privileges = self.request_peer.user_privileges - bot_privileges = self.request_peer.bot_privileges + user_privileges = self.request_chat.user_privileges + bot_privileges = self.request_chat.bot_privileges user_admin_rights = raw.types.ChatAdminRights( change_info=user_privileges.can_change_info, From b65279046ec64c2913fce856d07ef2ef2f613296 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Thu, 8 May 2025 16:21:42 +0300 Subject: [PATCH 21/39] Update upgraded gift regex Signed-off-by: wulan17 --- pyrogram/client.py | 1 + pyrogram/methods/payments/get_upgraded_gift.py | 2 +- pyrogram/methods/payments/set_pinned_gifts.py | 4 ++-- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index 1e8fef35..52b8aba0 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -231,6 +231,7 @@ class Client(Methods): PARENT_DIR = Path(sys.argv[0]).parent INVITE_LINK_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:joinchat/|\+))([\w-]+)$") + UPGRADED_GIFT_RE = re.compile(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:nft/|\+))([\w-]+)$") WORKERS = min(32, (os.cpu_count() or 0) + 4) # os.cpu_count() can be None WORKDIR = PARENT_DIR diff --git a/pyrogram/methods/payments/get_upgraded_gift.py b/pyrogram/methods/payments/get_upgraded_gift.py index 613be8dd..b91dc65d 100644 --- a/pyrogram/methods/payments/get_upgraded_gift.py +++ b/pyrogram/methods/payments/get_upgraded_gift.py @@ -47,7 +47,7 @@ class GetUpgradedGift: # Get information about upgraded gift by slug gift = await client.get_upgraded_gift("SignetRing-903") """ - match = re.match(r"^(?:https?://)?(?:www\.)?(?:t(?:elegram)?\.(?:org|me|dog)/(?:nft/|\+))([\w-]+)$", link) + match = self.UPGRADED_GIFT_RE.match(link) if match: slug = match.group(1) diff --git a/pyrogram/methods/payments/set_pinned_gifts.py b/pyrogram/methods/payments/set_pinned_gifts.py index 56352d43..ce7318b9 100644 --- a/pyrogram/methods/payments/set_pinned_gifts.py +++ b/pyrogram/methods/payments/set_pinned_gifts.py @@ -62,8 +62,8 @@ class SetPinnedGifts: if not isinstance(gift, str): raise ValueError(f"gift id has to be str, but {type(gift)} was provided") - saved_gift_match = re.match(r"^(-\d+)_(\d+)$", gift) - slug_match = self.UPGRADED_GIFT_RE.match(gift) + saved_gift_match = re.match(r"^(\d+)_(\d+)$", str(gift)) + slug_match = self.UPGRADED_GIFT_RE.match(str(gift)) if saved_gift_match: stargifts.append( From dbcbadc400d7791561f736f41decf570e15b40eb Mon Sep 17 00:00:00 2001 From: wulan17 Date: Sat, 21 Jun 2025 19:43:58 +0700 Subject: [PATCH 22/39] pyrofork: Add back reverse parameter in get_chat_history Signed-off-by: wulan17 --- pyrogram/methods/messages/get_chat_history.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/pyrogram/methods/messages/get_chat_history.py b/pyrogram/methods/messages/get_chat_history.py index fff96c7c..544b3cb2 100644 --- a/pyrogram/methods/messages/get_chat_history.py +++ b/pyrogram/methods/messages/get_chat_history.py @@ -33,7 +33,8 @@ async def get_chunk( from_message_id: int = 0, from_date: datetime = utils.zero_datetime(), min_id: int = 0, - max_id: int = 0 + max_id: int = 0, + reverse: Optional[bool] = None ): messages = await client.invoke( raw.functions.messages.GetHistory( @@ -48,6 +49,8 @@ async def get_chunk( ), sleep_threshold=60 ) + if reverse: + messages.messages.reverse() return await utils.parse_messages(client, messages, replies=0) @@ -61,7 +64,8 @@ class GetChatHistory: offset_id: int = 0, offset_date: datetime = utils.zero_datetime(), min_id: int = 0, - max_id: int = 0 + max_id: int = 0, + reverse: Optional[bool] = None ) -> Optional[AsyncGenerator["types.Message", None]]: """Get messages from a chat history. @@ -96,6 +100,9 @@ class GetChatHistory: max_id: (``int``, *optional*): The maximum message id. you will not get any message which have id greater than max_id. + reverse (``bool``, *optional*): + Pass True to retrieve the messages in reversed order (from older to most recent). + Returns: ``Generator``: A generator yielding :obj:`~pyrogram.types.Message` objects. @@ -118,7 +125,8 @@ class GetChatHistory: from_message_id=offset_id, from_date=offset_date, min_id=min_id, - max_id=max_id + max_id=max_id, + reverse=reverse ) if not messages: From fd4eb09f7a17e3d9f5e5404920c109476c9384a3 Mon Sep 17 00:00:00 2001 From: KurimuzonAkuma Date: Tue, 30 Apr 2024 16:22:00 +0300 Subject: [PATCH 23/39] Add get_call_members method Signed-off-by: gudmeong Signed-off-by: wulan17 --- compiler/docs/compiler.py | 5 + pyrogram/methods/__init__.py | 2 + pyrogram/methods/phone/__init__.py | 25 +++ pyrogram/methods/phone/get_call_members.py | 103 ++++++++++++ pyrogram/types/user_and_chats/__init__.py | 2 + .../types/user_and_chats/group_call_member.py | 149 ++++++++++++++++++ 6 files changed, 286 insertions(+) create mode 100644 pyrogram/methods/phone/__init__.py create mode 100644 pyrogram/methods/phone/get_call_members.py create mode 100644 pyrogram/types/user_and_chats/group_call_member.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 728a832c..24eeb19f 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -379,6 +379,10 @@ def pyrogram_api(): upgrade_gift get_stars_balance """, + phone=""" + Phone + get_call_members + """, password=""" Password enable_cloud_password @@ -514,6 +518,7 @@ def pyrogram_api(): PeerUser PeerChannel BotInfo + GroupCallMember ChatColor CollectibleItemInfo BotVerification diff --git a/pyrogram/methods/__init__.py b/pyrogram/methods/__init__.py index e700b0cc..dce6ef02 100644 --- a/pyrogram/methods/__init__.py +++ b/pyrogram/methods/__init__.py @@ -29,6 +29,7 @@ from .password import Password from .pyromod import Pyromod from .stickers import Stickers from .payments import Payments +from .phone import Phone from .users import Users from .utilities import Utilities from .business import TelegramBusiness @@ -42,6 +43,7 @@ class Methods( Password, Pyromod, Payments, + Phone, Chats, Stickers, Users, diff --git a/pyrogram/methods/phone/__init__.py b/pyrogram/methods/phone/__init__.py new file mode 100644 index 00000000..d2cff63d --- /dev/null +++ b/pyrogram/methods/phone/__init__.py @@ -0,0 +1,25 @@ +# 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 .get_call_members import GetCallMembers + + +class Phone( + GetCallMembers +): + pass diff --git a/pyrogram/methods/phone/get_call_members.py b/pyrogram/methods/phone/get_call_members.py new file mode 100644 index 00000000..8fabc1d9 --- /dev/null +++ b/pyrogram/methods/phone/get_call_members.py @@ -0,0 +1,103 @@ +# 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 typing import Union, AsyncGenerator + +import pyrogram +from pyrogram import types, raw + + +class GetCallMembers: + async def get_call_members( + self: "pyrogram.Client", + chat_id: Union[int, str], + limit: int = 0 + ) -> AsyncGenerator["types.GroupCallMember", None]: + """Get the members list of a chat call. + + A chat can be either a basic group or a supergroup. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + limit (``int``, *optional*): + Limits the number of members to be retrieved. + + Returns: + ``Generator``: On success, a generator yielding :obj:`~pyrogram.types.GroupCallMember` objects is returned. + + Example: + .. code-block:: python + + # Get members + async for member in app.get_call_members(chat_id): + print(member) + """ + peer = await self.resolve_peer(chat_id) + + if isinstance(peer, raw.types.InputPeerChannel): + r = await self.invoke(raw.functions.channels.GetFullChannel(channel=peer)) + elif isinstance(peer, raw.types.InputPeerChat): + r = await self.invoke(raw.functions.messages.GetFullChat(chat_id=peer.chat_id)) + else: + raise ValueError("Target chat should be group, supergroup or channel.") + + full_chat = r.full_chat + + if not getattr(full_chat, "call", None): + raise ValueError("There is no active call in this chat.") + + current = 0 + offset = "" + total = abs(limit) or (1 << 31) - 1 + limit = min(20, total) + + while True: + r = await self.invoke( + raw.functions.phone.GetGroupParticipants( + call=full_chat.call, + ids=[], + sources=[], + offset=offset, + limit=limit + ), + sleep_threshold=60 + ) + + users = {u.id: u for u in r.users} + chats = {c.id: c for c in r.chats} + members = [ + types.GroupCallMember._parse(self, member, users, chats) + for member in r.participants + ] + + if not members: + return + + offset = r.next_offset + + for member in members: + yield member + + current += 1 + + if current >= total: + return diff --git a/pyrogram/types/user_and_chats/__init__.py b/pyrogram/types/user_and_chats/__init__.py index 9a992d55..bc6c6ddc 100644 --- a/pyrogram/types/user_and_chats/__init__.py +++ b/pyrogram/types/user_and_chats/__init__.py @@ -43,6 +43,7 @@ from .chat_reactions import ChatReactions from .dialog import Dialog from .emoji_status import EmojiStatus from .folder import Folder +from .group_call_member import GroupCallMember from .invite_link_importer import InviteLinkImporter from .restriction import Restriction from .user import User @@ -106,5 +107,6 @@ __all__ = [ "ChatPrivileges", "ChatJoiner", "EmojiStatus", + "GroupCallMember", "ChatReactions" ] diff --git a/pyrogram/types/user_and_chats/group_call_member.py b/pyrogram/types/user_and_chats/group_call_member.py new file mode 100644 index 00000000..551db102 --- /dev/null +++ b/pyrogram/types/user_and_chats/group_call_member.py @@ -0,0 +1,149 @@ +# 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 Dict + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object + + +class GroupCallMember(Object): + """Contains information about one member of a group call. + + Parameters: + chat (:obj:`~pyrogram.types.Chat`, *optional*): + Information about the user or chat. + + date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant join this group call. + + active_date (:py:obj:`~datetime.datetime`, *optional*): + Date when this participant last active in this group call. + + volume (``int``, *optional*): + Volume, if not set the volume is set to 100%. + + can_self_unmute (``bool``, *optional*): + Whether the participant can unmute themselves. + + is_muted (``bool``, *optional*): + Whether the participant is muted. + + is_left (``bool``, *optional*): + Whether the participant has left. + + is_just_joined (``bool``, *optional*): + Whether the participant has just joined. + + is_muted_by_you (``bool``, *optional*): + Whether this participant was muted by the current user. + + is_volume_by_admin (``bool``, *optional*): + Whether our volume can only changed by an admin. + + is_self (``bool``, *optional*): + Whether this participant is the current user. + + is_video_joined (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_hand_raised (``bool``, *optional*): + Whether this participant is raised hand. + + is_video_enabled (``bool``, *optional*): + Whether this participant is currently broadcasting video. + + is_screen_sharing_enabled (``bool``, *optional*): + Whether this participant is currently shared screen. + """ + + def __init__( + self, + *, + client: "pyrogram.Client" = None, + chat: "types.Chat" = None, + date: datetime = None, + active_date: datetime = None, + volume: int = None, + can_self_unmute: bool = None, + is_muted: bool = None, + is_left: bool = None, + is_just_joined: bool = None, + is_muted_by_you: bool = None, + is_volume_by_admin: bool = None, + is_self: bool = None, + is_video_joined: bool = None, + is_hand_raised: bool = None, + is_video_enabled: bool = None, + is_screen_sharing_enabled: bool = None + ): + super().__init__(client) + + self.chat = chat + self.date = date + self.active_date = active_date + self.volume = volume + self.can_self_unmute = can_self_unmute + self.is_muted = is_muted + self.is_left = is_left + self.is_just_joined = is_just_joined + self.is_muted_by_you = is_muted_by_you + self.is_volume_by_admin = is_volume_by_admin + self.is_self = is_self + self.is_video_joined = is_video_joined + self.is_hand_raised = is_hand_raised + self.is_video_enabled = is_video_enabled + self.is_screen_sharing_enabled = is_screen_sharing_enabled + + @staticmethod + def _parse( + client: "pyrogram.Client", + member: "raw.types.GroupCallParticipant", + users: Dict[int, "raw.base.User"], + chats: Dict[int, "raw.base.Chat"] + ) -> "GroupCallMember": + peer = member.peer + peer_id = utils.get_raw_peer_id(peer) + + parsed_chat = types.Chat._parse_chat( + client, + users[peer_id] if isinstance(peer, raw.types.PeerUser) else chats[peer_id], + ) + + parsed_chat.bio = getattr(member, "about", None) + + return GroupCallMember( + chat=parsed_chat, + date=utils.timestamp_to_datetime(member.date), + active_date=utils.timestamp_to_datetime(member.active_date), + volume=getattr(member, "volume", None), + can_self_unmute=member.can_self_unmute, + is_muted=member.muted, + is_left=member.left, + is_just_joined=member.just_joined, + is_muted_by_you=member.muted_by_you, + is_volume_by_admin=member.volume_by_admin, + is_self=member.is_self, + is_video_joined=member.video_joined, + is_hand_raised=bool(getattr(member, "raise_hand_rating", None)), + is_video_enabled=bool(getattr(member, "video", None)), + is_screen_sharing_enabled=bool(getattr(member, "presentation", None)), + client=client + ) From 52abec6e010907185b580f74f18b07fc68643b96 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Wed, 25 Jun 2025 19:10:50 +0700 Subject: [PATCH 24/39] pyrofork: fix NoneType exception in filters Signed-off-by: wulan17 --- pyrogram/filters.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index d152e32a..a5f97560 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -1035,7 +1035,7 @@ class user(Filter, set): async def __call__(self, _, message: Message): is_usernames_in_filters = False - if message.from_user.usernames: + if message.from_user and message.from_user.usernames: for username in message.from_user.usernames: if ( username.username in self @@ -1078,7 +1078,7 @@ class chat(Filter, set): async def __call__(self, _, message: Union[Message, Story]): if isinstance(message, Story): is_usernames_in_filters = False - if message.sender_chat.usernames: + if message.sender_chat and message.sender_chat.usernames: for username in message.sender_chat.usernames: if ( username.username in self @@ -1107,7 +1107,7 @@ class chat(Filter, set): ) or is_usernames_in_filters else: is_usernames_in_filters = False - if message.chat.usernames: + if message.chat and message.chat.usernames: for username in message.chat.usernames: if ( username.username in self From 12d9297c0204a85dcf6d45a241dac2bd71addfe3 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Wed, 25 Jun 2025 19:16:02 +0700 Subject: [PATCH 25/39] pyrofork: Bump version to 2.3.67 Signed-off-by: wulan17 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 36f5975d..915319c5 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -18,7 +18,7 @@ # along with Pyrofork. If not, see . __fork_name__ = "PyroFork" -__version__ = "2.3.66" +__version__ = "2.3.67" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2022-present Mayuri-Chan " From cc4eb21b845bb9180b64452176a15180d4e9f790 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 15:11:37 +0000 Subject: [PATCH 26/39] build(deps): bump sphinx-immaterial from 0.12.4 to 0.13.4 Bumps [sphinx-immaterial](https://github.com/jbms/sphinx-immaterial) from 0.12.4 to 0.13.4. - [Release notes](https://github.com/jbms/sphinx-immaterial/releases) - [Commits](https://github.com/jbms/sphinx-immaterial/compare/v0.12.4...v0.13.4) --- updated-dependencies: - dependency-name: sphinx-immaterial dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] --- pyproject.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index 83d9d16a..38bd2145 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -60,7 +60,7 @@ dev = [ docs = [ "sphinx", - "sphinx-immaterial==0.12.4", + "sphinx-immaterial==0.12.5", "sphinx_copybutton", "sphinx-autobuild", "tornado>=6.3.3" From 1ba1a051c4e0de9ed66efe5261b6cae689caf7e4 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Sat, 5 Jul 2025 20:47:26 +0700 Subject: [PATCH 27/39] pyrofork: Update API schema to Layer 205 Signed-off-by: wulan17 --- compiler/api/source/main_api.tl | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 92956c78..74354aac 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -55,6 +55,7 @@ inputMediaDice#e66fbf7b emoticon:string = InputMedia; inputMediaStory#89fdd778 peer:InputPeer id:int = InputMedia; inputMediaWebPage#c21b8849 flags:# force_large_media:flags.0?true force_small_media:flags.1?true optional:flags.2?true url:string = InputMedia; inputMediaPaidMedia#c4103386 flags:# stars_amount:long extended_media:Vector payload:flags.0?string = InputMedia; +inputMediaTodo#9fc55fde todo:TodoList = InputMedia; inputChatPhotoEmpty#1ca48f57 = InputChatPhoto; inputChatUploadedPhoto#bdcdaec0 flags:# file:flags.0?InputFile video:flags.1?InputFile video_start_ts:flags.2?double video_emoji_markup:flags.3?VideoSize = InputChatPhoto; @@ -126,7 +127,7 @@ chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:f messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; message#eabcdd4d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long = Message; -messageService#d3d28540 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; +messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; messageMediaEmpty#3ded6320 = MessageMedia; messageMediaPhoto#695150d7 flags:# spoiler:flags.3?true photo:flags.0?Photo ttl_seconds:flags.2?int = MessageMedia; @@ -145,6 +146,7 @@ messageMediaStory#68cb6283 flags:# via_mention:flags.1?true peer:Peer id:int sto messageMediaGiveaway#aa073beb flags:# only_new_subscribers:flags.0?true winners_are_visible:flags.2?true channels:Vector countries_iso2:flags.1?Vector prize_description:flags.3?string quantity:int months:flags.4?int stars:flags.5?long until_date:int = MessageMedia; messageMediaGiveawayResults#ceaa3ea1 flags:# only_new_subscribers:flags.0?true refunded:flags.2?true channel_id:long additional_peers_count:flags.3?int launch_msg_id:int winners_count:int unclaimed_count:int winners:Vector months:flags.4?int stars:flags.5?long prize_description:flags.1?string until_date:int = MessageMedia; messageMediaPaidMedia#a8852491 stars_amount:long extended_media:Vector = MessageMedia; +messageMediaToDo#8a53b014 flags:# todo:TodoList completions:flags.0?Vector = MessageMedia; messageActionEmpty#b6aef7b0 = MessageAction; messageActionChatCreate#bd47cbad title:string users:Vector = MessageAction; @@ -197,6 +199,8 @@ messageActionStarGiftUnique#2e3ae60e flags:# upgrade:flags.0?true transferred:fl messageActionPaidMessagesRefunded#ac1f1fcd count:int stars:long = MessageAction; messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags.0?true stars:long = MessageAction; messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; +messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; +messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -1416,9 +1420,9 @@ account.resetPasswordFailedWait#e3779861 retry_date:int = account.ResetPasswordR account.resetPasswordRequestedWait#e9effc7d until_date:int = account.ResetPasswordResult; account.resetPasswordOk#e926d63e = account.ResetPasswordResult; -sponsoredMessage#4d93a990 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string = SponsoredMessage; +sponsoredMessage#7dbf8673 flags:# recommended:flags.5?true can_report:flags.12?true random_id:bytes url:string title:string message:string entities:flags.1?Vector photo:flags.6?Photo media:flags.14?MessageMedia color:flags.13?PeerColor button_text:string sponsor_info:flags.7?string additional_info:flags.8?string min_display_duration:flags.15?int max_display_duration:flags.15?int = SponsoredMessage; -messages.sponsoredMessages#c9ee1d87 flags:# posts_between:flags.0?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; +messages.sponsoredMessages#ffda656d flags:# posts_between:flags.0?int start_delay:flags.1?int between_delay:flags.2?int messages:Vector chats:Vector users:Vector = messages.SponsoredMessages; messages.sponsoredMessagesEmpty#1839490f = messages.SponsoredMessages; searchResultsCalendarPeriod#c9b0539f date:int min_msg_id:int max_msg_id:int count:int = SearchResultsCalendarPeriod; @@ -1724,7 +1728,7 @@ storyReactionPublicRepost#cfcd0f13 peer_id:Peer story:StoryItem = StoryReaction; stories.storyReactionsList#aa5f789c flags:# count:int reactions:Vector chats:Vector users:Vector next_offset:flags.0?string = stories.StoryReactionsList; savedDialog#bd87cb6c flags:# pinned:flags.2?true peer:Peer top_message:int = SavedDialog; -monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; +monoForumDialog#64407ea7 flags:# unread_mark:flags.3?true nopaid_messages_exception:flags.4?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_reactions_count:int draft:flags.1?DraftMessage = SavedDialog; messages.savedDialogs#f83ae221 dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; messages.savedDialogsSlice#44ba9dd9 count:int dialogs:Vector messages:Vector chats:Vector users:Vector = messages.SavedDialogs; @@ -1992,6 +1996,12 @@ stories.canSendStoryCount#c387c04e count_remains:int = stories.CanSendStoryCount pendingSuggestion#e7e82e12 suggestion:string title:TextWithEntities description:TextWithEntities url:string = PendingSuggestion; +todoItem#cba9a52f id:int title:TextWithEntities = TodoItem; + +todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:flags.1?true title:TextWithEntities list:Vector = TodoList; + +todoCompletion#4cc120b7 id:int completed_by:long date:int = TodoCompletion; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2143,8 +2153,8 @@ account.toggleSponsoredMessages#b9d9a38d enabled:Bool = Bool; account.getReactionsNotifySettings#6dd654c = ReactionsNotifySettings; account.setReactionsNotifySettings#316ce548 settings:ReactionsNotifySettings = ReactionsNotifySettings; account.getCollectibleEmojiStatuses#2e7b4543 hash:long = account.EmojiStatuses; -account.addNoPaidMessagesException#6f688aa7 flags:# refund_charged:flags.0?true user_id:InputUser = Bool; -account.getPaidMessagesRevenue#f1266f38 user_id:InputUser = account.PaidMessagesRevenue; +account.getPaidMessagesRevenue#19ba4a67 flags:# parent_peer:flags.0?InputPeer user_id:InputUser = account.PaidMessagesRevenue; +account.toggleNoPaidMessagesException#fe2eda76 flags:# refund_charged:flags.0?true require_payment:flags.2?true parent_peer:flags.1?InputPeer user_id:InputUser = Bool; users.getUsers#d91a548 id:Vector = Vector; users.getFullUser#b60f5918 id:InputUser = users.UserFull; @@ -2399,13 +2409,15 @@ messages.getPaidReactionPrivacy#472455aa = Updates; messages.viewSponsoredMessage#269e3643 random_id:bytes = Bool; messages.clickSponsoredMessage#8235057e flags:# media:flags.0?true fullscreen:flags.1?true random_id:bytes = Bool; messages.reportSponsoredMessage#12cbf0c4 random_id:bytes option:bytes = channels.SponsoredMessageReportResult; -messages.getSponsoredMessages#9bd2f439 peer:InputPeer = messages.SponsoredMessages; +messages.getSponsoredMessages#3d6ce850 flags:# peer:InputPeer msg_id:flags.0?int = messages.SponsoredMessages; messages.savePreparedInlineMessage#f21f7f2f flags:# result:InputBotInlineResult user_id:InputUser peer_types:flags.0?Vector = messages.BotPreparedInlineMessage; messages.getPreparedInlineMessage#857ebdb8 bot:InputUser id:string = messages.PreparedInlineMessage; messages.searchStickers#29b1c66a flags:# emojis:flags.0?true q:string emoticon:string lang_code:Vector offset:int limit:int hash:long = messages.FoundStickers; messages.reportMessagesDelivery#5a6d7395 flags:# push:flags.0?true peer:InputPeer id:Vector = Bool; messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids:Vector = messages.SavedDialogs; messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; +messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; +messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2723,4 +2735,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; -// LAYER 204 +// LAYER 205 From cb19b742adccc0bb71937b2f2d32ebfba57aff1a Mon Sep 17 00:00:00 2001 From: wulan17 Date: Sat, 5 Jul 2025 21:04:48 +0700 Subject: [PATCH 28/39] pyrofork: Update API schema to Layer 206 Signed-off-by: wulan17 --- compiler/api/source/main_api.tl | 58 +++++++++++++++------------------ 1 file changed, 26 insertions(+), 32 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 74354aac..9d8885db 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -113,7 +113,7 @@ channel#fe685355 flags:# creator:flags.0?true left:flags.2?true broadcast:flags. channelForbidden#17d493d5 flags:# broadcast:flags.5?true megagroup:flags.8?true id:long access_hash:long title:string until_date:flags.16?int = Chat; chatFull#2633421b flags:# can_set_username:flags.7?true has_scheduled:flags.8?true translations_disabled:flags.19?true id:long about:string participants:ChatParticipants chat_photo:flags.2?Photo notify_settings:PeerNotifySettings exported_invite:flags.13?ExportedChatInvite bot_info:flags.3?Vector pinned_msg_id:flags.6?int folder_id:flags.11?int call:flags.12?InputGroupCall ttl_period:flags.14?int groupcall_default_join_as:flags.15?Peer theme_emoticon:flags.16?string requests_pending:flags.17?int recent_requesters:flags.17?Vector available_reactions:flags.18?ChatReactions reactions_limit:flags.20?int = ChatFull; -channelFull#52d6806b flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int = ChatFull; +channelFull#e07429de flags:# can_view_participants:flags.3?true can_set_username:flags.6?true can_set_stickers:flags.7?true hidden_prehistory:flags.10?true can_set_location:flags.16?true has_scheduled:flags.19?true can_view_stats:flags.20?true blocked:flags.22?true flags2:# can_delete_channel:flags2.0?true antispam:flags2.1?true participants_hidden:flags2.2?true translations_disabled:flags2.3?true stories_pinned_available:flags2.5?true view_forum_as_messages:flags2.6?true restricted_sponsored:flags2.11?true can_view_revenue:flags2.12?true paid_media_allowed:flags2.14?true can_view_stars_revenue:flags2.15?true paid_reactions_available:flags2.16?true stargifts_available:flags2.19?true paid_messages_available:flags2.20?true id:long about:string participants_count:flags.0?int admins_count:flags.1?int kicked_count:flags.2?int banned_count:flags.2?int online_count:flags.13?int read_inbox_max_id:int read_outbox_max_id:int unread_count:int chat_photo:Photo notify_settings:PeerNotifySettings exported_invite:flags.23?ExportedChatInvite bot_info:Vector migrated_from_chat_id:flags.4?long migrated_from_max_id:flags.4?int pinned_msg_id:flags.5?int stickerset:flags.8?StickerSet available_min_id:flags.9?int folder_id:flags.11?int linked_chat_id:flags.14?long location:flags.15?ChannelLocation slowmode_seconds:flags.17?int slowmode_next_send_date:flags.18?int stats_dc:flags.12?int pts:int call:flags.21?InputGroupCall ttl_period:flags.24?int pending_suggestions:flags.25?Vector groupcall_default_join_as:flags.26?Peer theme_emoticon:flags.27?string requests_pending:flags.28?int recent_requesters:flags.28?Vector default_send_as:flags.29?Peer available_reactions:flags.30?ChatReactions reactions_limit:flags2.13?int stories:flags2.4?PeerStories wallpaper:flags2.7?WallPaper boosts_applied:flags2.8?int boosts_unrestrict:flags2.9?int emojiset:flags2.10?StickerSet bot_verification:flags2.17?BotVerification stargifts_count:flags2.18?int send_paid_messages_stars:flags2.21?long = ChatFull; chatParticipant#c02d4007 user_id:long inviter_id:long date:int = ChatParticipant; chatParticipantCreator#e46bcee4 user_id:long = ChatParticipant; @@ -126,7 +126,7 @@ chatPhotoEmpty#37c1011c = ChatPhoto; chatPhoto#1c6e1c11 flags:# has_video:flags.0?true photo_id:long stripped_thumb:flags.1?bytes dc_id:int = ChatPhoto; messageEmpty#90a6ca84 flags:# id:int peer_id:flags.0?Peer = Message; -message#eabcdd4d flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long = Message; +message#9815cec8 flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true silent:flags.13?true post:flags.14?true from_scheduled:flags.18?true legacy:flags.19?true edit_hide:flags.21?true pinned:flags.24?true noforwards:flags.26?true invert_media:flags.27?true flags2:# offline:flags2.1?true video_processing_pending:flags2.4?true paid_suggested_post_stars:flags2.8?true paid_suggested_post_ton:flags2.9?true id:int from_id:flags.8?Peer from_boosts_applied:flags.29?int peer_id:Peer saved_peer_id:flags.28?Peer fwd_from:flags.2?MessageFwdHeader via_bot_id:flags.11?long via_business_bot_id:flags2.0?long reply_to:flags.3?MessageReplyHeader date:int message:string media:flags.9?MessageMedia reply_markup:flags.6?ReplyMarkup entities:flags.7?Vector views:flags.10?int forwards:flags.10?int replies:flags.23?MessageReplies edit_date:flags.15?int post_author:flags.16?string grouped_id:flags.17?long reactions:flags.20?MessageReactions restriction_reason:flags.22?Vector ttl_period:flags.25?int quick_reply_shortcut_id:flags.30?int effect:flags2.2?long factcheck:flags2.3?FactCheck report_delivery_until_date:flags2.5?int paid_message_stars:flags2.6?long suggested_post:flags2.7?SuggestedPost = Message; messageService#7a800e0a flags:# out:flags.1?true mentioned:flags.4?true media_unread:flags.5?true reactions_are_possible:flags.9?true silent:flags.13?true post:flags.14?true legacy:flags.19?true id:int from_id:flags.8?Peer peer_id:Peer saved_peer_id:flags.28?Peer reply_to:flags.3?MessageReplyHeader date:int action:MessageAction reactions:flags.20?MessageReactions ttl_period:flags.25?int = Message; messageMediaEmpty#3ded6320 = MessageMedia; @@ -201,6 +201,10 @@ messageActionPaidMessagesPrice#84b88578 flags:# broadcast_messages_allowed:flags messageActionConferenceCall#2ffe2f7a flags:# missed:flags.0?true active:flags.1?true video:flags.4?true call_id:long duration:flags.2?int other_participants:flags.3?Vector = MessageAction; messageActionTodoCompletions#cc7c5c89 completed:Vector incompleted:Vector = MessageAction; messageActionTodoAppendTasks#c7edbc83 list:Vector = MessageAction; +messageActionSuggestedPostApproval#ee7a1596 flags:# rejected:flags.0?true balance_too_low:flags.1?true reject_comment:flags.2?string schedule_date:flags.3?int price:flags.4?StarsAmount = MessageAction; +messageActionSuggestedPostSuccess#95ddcf69 price:StarsAmount = MessageAction; +messageActionSuggestedPostRefund#69f916f8 flags:# payer_initiated:flags.0?true = MessageAction; +messageActionGiftTon#a8a3c699 flags:# currency:string amount:long crypto_currency:string crypto_amount:long transaction_id:flags.0?string = MessageAction; dialog#d58a08c6 flags:# pinned:flags.2?true unread_mark:flags.3?true view_forum_as_messages:flags.6?true peer:Peer top_message:int read_inbox_max_id:int read_outbox_max_id:int unread_count:int unread_mentions_count:int unread_reactions_count:int notify_settings:PeerNotifySettings pts:flags.0?int draft:flags.1?DraftMessage folder_id:flags.4?int ttl_period:flags.5?int = Dialog; dialogFolder#71bd134c flags:# pinned:flags.2?true folder:Folder peer:Peer top_message:int unread_muted_peers_count:int unread_unmuted_peers_count:int unread_muted_messages_count:int unread_unmuted_messages_count:int = Dialog; @@ -438,7 +442,6 @@ updateBotNewBusinessMessage#9ddb347c flags:# connection_id:string message:Messag updateBotEditBusinessMessage#7df587c flags:# connection_id:string message:Message reply_to_message:flags.0?Message qts:int = Update; updateBotDeleteBusinessMessage#a02a982e connection_id:string peer:Peer messages:Vector qts:int = Update; updateNewStoryReaction#1824e40b story_id:int peer:Peer reaction:Reaction = Update; -updateBroadcastRevenueTransactions#dfd961f5 peer:Peer balances:BroadcastRevenueBalances = Update; 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; updateStarsRevenueStatus#a584b019 peer:Peer status:StarsRevenueStatus = Update; @@ -448,6 +451,7 @@ updateSentPhoneCode#504aa18f sent_code:auth.SentCode = Update; updateGroupCallChainBlocks#a477288f call:InputGroupCall sub_chain_id:int blocks:Vector next_offset:int = Update; updateReadMonoForumInbox#77b0e372 channel_id:long saved_peer_id:Peer read_max_id:int = Update; updateReadMonoForumOutbox#a4a79376 channel_id:long saved_peer_id:Peer read_max_id:int = Update; +updateMonoForumNoPaidException#9f812b08 flags:# exception:flags.0?true channel_id:long saved_peer_id:Peer = Update; updates.state#a56c2a3e pts:int qts:int date:int seq:int unread_count:int = updates.State; @@ -657,6 +661,7 @@ inputStickerSetEmojiGenericAnimations#4c4d4ce = InputStickerSet; inputStickerSetEmojiDefaultStatuses#29d0f5ee = InputStickerSet; inputStickerSetEmojiDefaultTopicIcons#44c1f8e9 = InputStickerSet; inputStickerSetEmojiChannelDefaultStatuses#49748553 = InputStickerSet; +inputStickerSetTonGifts#1cf671a0 = InputStickerSet; stickerSet#2dd14edc flags:# archived:flags.1?true official:flags.2?true masks:flags.3?true emojis:flags.7?true text_color:flags.9?true channel_emoji_status:flags.10?true creator:flags.11?true installed_date:flags.0?int id:long access_hash:long title:string short_name:string thumbs:flags.4?Vector thumb_dc_id:flags.4?int thumb_version:flags.4?int thumb_document_id:flags.8?long count:int hash:int = StickerSet; @@ -835,7 +840,7 @@ contacts.topPeers#70b772a8 categories:Vector chats:Vector< contacts.topPeersDisabled#b52c939d = contacts.TopPeers; draftMessageEmpty#1b0c841a flags:# date:flags.0?int = DraftMessage; -draftMessage#2d65321f flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long = DraftMessage; +draftMessage#96eaa5eb flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo message:string entities:flags.3?Vector media:flags.5?InputMedia date:int effect:flags.7?long suggested_post:flags.8?SuggestedPost = DraftMessage; messages.featuredStickersNotModified#c6dc0c66 count:int = messages.FeaturedStickers; messages.featuredStickers#be382906 flags:# premium:flags.0?true hash:long count:int sets:Vector unread:Vector = messages.FeaturedStickers; @@ -1215,7 +1220,7 @@ chatOnlines#f041e250 onlines:int = ChatOnlines; statsURL#47a971e0 url:string = StatsURL; -chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true = ChatAdminRights; +chatAdminRights#5fb224d5 flags:# change_info:flags.0?true post_messages:flags.1?true edit_messages:flags.2?true delete_messages:flags.3?true ban_users:flags.4?true invite_users:flags.5?true pin_messages:flags.7?true add_admins:flags.9?true anonymous:flags.10?true manage_call:flags.11?true other:flags.12?true manage_topics:flags.13?true post_stories:flags.14?true edit_stories:flags.15?true delete_stories:flags.16?true manage_direct_messages:flags.17?true = ChatAdminRights; chatBannedRights#9f120418 flags:# view_messages:flags.0?true send_messages:flags.1?true send_media:flags.2?true send_stickers:flags.3?true send_gifs:flags.4?true send_games:flags.5?true send_inline:flags.6?true embed_links:flags.7?true send_polls:flags.8?true change_info:flags.10?true invite_users:flags.15?true pin_messages:flags.17?true manage_topics:flags.18?true send_photos:flags.19?true send_videos:flags.20?true send_roundvideos:flags.21?true send_audios:flags.22?true send_voices:flags.23?true send_docs:flags.24?true send_plain:flags.25?true until_date:int = ChatBannedRights; @@ -1833,23 +1838,11 @@ channels.sponsoredMessageReportResultChooseOption#846f9e42 title:string options: channels.sponsoredMessageReportResultAdsHidden#3e3bcf2f = channels.SponsoredMessageReportResult; channels.sponsoredMessageReportResultReported#ad798849 = channels.SponsoredMessageReportResult; -stats.broadcastRevenueStats#5407e297 top_hours_graph:StatsGraph revenue_graph:StatsGraph balances:BroadcastRevenueBalances usd_rate:double = stats.BroadcastRevenueStats; - -stats.broadcastRevenueWithdrawalUrl#ec659737 url:string = stats.BroadcastRevenueWithdrawalUrl; - -broadcastRevenueTransactionProceeds#557e2cc4 amount:long from_date:int to_date:int = BroadcastRevenueTransaction; -broadcastRevenueTransactionWithdrawal#5a590978 flags:# pending:flags.0?true failed:flags.2?true amount:long date:int provider:string transaction_date:flags.1?int transaction_url:flags.1?string = BroadcastRevenueTransaction; -broadcastRevenueTransactionRefund#42d30d2e amount:long date:int provider:string = BroadcastRevenueTransaction; - -stats.broadcastRevenueTransactions#87158466 count:int transactions:Vector = stats.BroadcastRevenueTransactions; - reactionNotificationsFromContacts#bac3a61a = ReactionNotificationsFrom; reactionNotificationsFromAll#4b9e22a0 = ReactionNotificationsFrom; reactionsNotifySettings#56e34970 flags:# messages_notify_from:flags.0?ReactionNotificationsFrom stories_notify_from:flags.1?ReactionNotificationsFrom sound:NotificationSound show_previews:Bool = ReactionsNotifySettings; -broadcastRevenueBalances#c3ff71e7 flags:# withdrawal_enabled:flags.0?true current_balance:long available_balance:long overall_revenue:long = BroadcastRevenueBalances; - availableEffect#93c3e27e flags:# premium_required:flags.2?true id:long emoticon:string static_icon_id:flags.0?long effect_sticker_id:long effect_animation_id:flags.1?long = AvailableEffect; messages.availableEffectsNotModified#d1ed9a5b = messages.AvailableEffects; @@ -1868,7 +1861,7 @@ starsTransactionPeerAPI#f9677aad = StarsTransactionPeer; starsTopupOption#bd915c0 flags:# extended:flags.1?true stars:long store_product:flags.0?string currency:string amount:long = StarsTopupOption; -starsTransaction#a39fd94a flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true id:string stars:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int = StarsTransaction; +starsTransaction#13659eb0 flags:# refund:flags.3?true pending:flags.4?true failed:flags.6?true gift:flags.10?true reaction:flags.11?true stargift_upgrade:flags.18?true business_transfer:flags.21?true stargift_resale:flags.22?true id:string amount:StarsAmount date:int peer:StarsTransactionPeer title:flags.0?string description:flags.1?string photo:flags.2?WebDocument transaction_date:flags.5?int transaction_url:flags.5?string bot_payload:flags.7?bytes msg_id:flags.8?int extended_media:flags.9?Vector subscription_period:flags.12?int giveaway_post_id:flags.13?int stargift:flags.14?StarGift floodskip_number:flags.15?int starref_commission_permille:flags.16?int starref_peer:flags.17?Peer starref_amount:flags.17?StarsAmount paid_messages:flags.19?int premium_gift_months:flags.20?int ads_proceeds_from_date:flags.23?int ads_proceeds_to_date:flags.23?int = StarsTransaction; payments.starsStatus#6c9ce8ed flags:# balance:StarsAmount subscriptions:flags.1?Vector subscriptions_next_offset:flags.2?string subscriptions_missing_balance:flags.4?long history:flags.3?Vector next_offset:flags.0?string chats:Vector users:Vector = payments.StarsStatus; @@ -1880,7 +1873,7 @@ geoPointAddress#de4c5d93 flags:# country_iso2:string state:flags.0?string city:f starsRevenueStatus#febe5491 flags:# withdrawal_enabled:flags.0?true current_balance:StarsAmount available_balance:StarsAmount overall_revenue:StarsAmount next_withdrawal_at:flags.1?int = StarsRevenueStatus; -payments.starsRevenueStats#c92bb73b revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; +payments.starsRevenueStats#6c207376 flags:# top_hours_graph:flags.0?StatsGraph revenue_graph:StatsGraph status:StarsRevenueStatus usd_rate:double = payments.StarsRevenueStats; payments.starsRevenueWithdrawalUrl#1dab80b7 url:string = payments.StarsRevenueWithdrawalUrl; @@ -1933,6 +1926,7 @@ payments.connectedStarRefBots#98d5ea1d count:int connected_bots:Vector users:Vector next_offset:flags.0?string = payments.SuggestedStarRefBots; starsAmount#bbb6b4a3 amount:long nanos:int = StarsAmount; +starsTonAmount#74aee3e0 amount:long = StarsAmount; messages.foundStickersNotModified#6010c534 flags:# next_offset:flags.0?int = messages.FoundStickers; messages.foundStickers#82c9e290 flags:# next_offset:flags.0?int hash:long stickers:Vector = messages.FoundStickers; @@ -2002,6 +1996,8 @@ todoList#49b92a26 flags:# others_can_append:flags.0?true others_can_complete:fla todoCompletion#4cc120b7 id:int completed_by:long date:int = TodoCompletion; +suggestedPost#e8e37e5 flags:# accepted:flags.1?true rejected:flags.2?true price:flags.3?StarsAmount schedule_date:flags.0?int = SuggestedPost; + ---functions--- invokeAfterMsg#cb9f372d {X:Type} msg_id:long query:!X = X; @@ -2198,9 +2194,9 @@ messages.deleteHistory#b08f922a flags:# just_clear:flags.0?true revoke:flags.1?t messages.deleteMessages#e58e95d2 flags:# revoke:flags.0?true id:Vector = messages.AffectedMessages; messages.receivedMessages#5a954c0 max_id:int = Vector; messages.setTyping#58943ee2 flags:# peer:InputPeer top_msg_id:flags.0?int action:SendMessageAction = Bool; -messages.sendMessage#fbf2340a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.sendMedia#a550cd78 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long = Updates; -messages.forwardMessages#38f0188c flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int allow_paid_stars:flags.21?long = Updates; +messages.sendMessage#fe05dc9a flags:# no_webpage:flags.1?true silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; +messages.sendMedia#ac55d9c1 flags:# silent:flags.5?true background:flags.6?true clear_draft:flags.7?true noforwards:flags.14?true update_stickersets_order:flags.15?true invert_media:flags.16?true allow_paid_floodskip:flags.19?true peer:InputPeer reply_to:flags.0?InputReplyTo media:InputMedia message:string random_id:long reply_markup:flags.2?ReplyMarkup entities:flags.3?Vector schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut effect:flags.18?long allow_paid_stars:flags.21?long suggested_post:flags.22?SuggestedPost = Updates; +messages.forwardMessages#978928ca flags:# silent:flags.5?true background:flags.6?true with_my_score:flags.8?true drop_author:flags.11?true drop_media_captions:flags.12?true noforwards:flags.14?true allow_paid_floodskip:flags.19?true from_peer:InputPeer id:Vector random_id:Vector to_peer:InputPeer top_msg_id:flags.9?int reply_to:flags.22?InputReplyTo schedule_date:flags.10?int send_as:flags.13?InputPeer quick_reply_shortcut:flags.17?InputQuickReplyShortcut video_timestamp:flags.20?int allow_paid_stars:flags.21?long suggested_post:flags.23?SuggestedPost = Updates; messages.reportSpam#cf1592db peer:InputPeer = Bool; messages.getPeerSettings#efd9a6a2 peer:InputPeer = messages.PeerSettings; messages.report#fc78af9b peer:InputPeer id:Vector option:bytes message:string = ReportResult; @@ -2250,7 +2246,7 @@ messages.editInlineBotMessage#83557dba flags:# no_webpage:flags.1?true invert_me messages.getBotCallbackAnswer#9342ca07 flags:# game:flags.1?true peer:InputPeer msg_id:int data:flags.0?bytes password:flags.2?InputCheckPasswordSRP = messages.BotCallbackAnswer; messages.setBotCallbackAnswer#d58f130a flags:# alert:flags.1?true query_id:long message:flags.0?string url:flags.2?string cache_time:int = Bool; messages.getPeerDialogs#e470bcfd peers:Vector = messages.PeerDialogs; -messages.saveDraft#d372c5ce flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long = Bool; +messages.saveDraft#54ae308e flags:# no_webpage:flags.1?true invert_media:flags.6?true reply_to:flags.4?InputReplyTo peer:InputPeer message:string entities:flags.3?Vector media:flags.5?InputMedia effect:flags.7?long suggested_post:flags.8?SuggestedPost = Bool; messages.getAllDrafts#6a3f8d65 = Updates; messages.getFeaturedStickers#64780b14 hash:long = messages.FeaturedStickers; messages.readFeaturedStickers#5b118126 id:Vector = Bool; @@ -2418,6 +2414,7 @@ messages.getSavedDialogsByID#6f6f9c96 flags:# parent_peer:flags.1?InputPeer ids: messages.readSavedHistory#ba4a3b5b parent_peer:InputPeer peer:InputPeer max_id:int = Bool; messages.toggleTodoCompleted#d3e03124 peer:InputPeer msg_id:int completed:Vector incompleted:Vector = Updates; messages.appendTodoList#21a61057 peer:InputPeer msg_id:int list:Vector = Updates; +messages.toggleSuggestedPostApproval#8107455c flags:# reject:flags.1?true peer:InputPeer msg_id:int schedule_date:flags.0?int reject_comment:flags.2?string = Updates; updates.getState#edd4882a = updates.State; updates.getDifference#19c2f763 flags:# pts:int pts_limit:flags.1?int pts_total_limit:flags.0?int date:int qts:int qts_limit:flags.2?int = updates.Difference; @@ -2576,14 +2573,14 @@ payments.applyGiftCode#f6e26854 slug:string = Updates; payments.getGiveawayInfo#f4239425 peer:InputPeer msg_id:int = payments.GiveawayInfo; payments.launchPrepaidGiveaway#5ff58f20 peer:InputPeer giveaway_id:long purpose:InputStorePaymentPurpose = Updates; payments.getStarsTopupOptions#c00ec7d3 = Vector; -payments.getStarsStatus#104fcfa7 peer:InputPeer = payments.StarsStatus; -payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; +payments.getStarsStatus#4ea9b3bf flags:# ton:flags.0?true peer:InputPeer = payments.StarsStatus; +payments.getStarsTransactions#69da4557 flags:# inbound:flags.0?true outbound:flags.1?true ascending:flags.2?true ton:flags.4?true subscription_id:flags.3?string peer:InputPeer offset:string limit:int = payments.StarsStatus; payments.sendStarsForm#7998c914 form_id:long invoice:InputInvoice = payments.PaymentResult; payments.refundStarsCharge#25ae8f4a user_id:InputUser charge_id:string = Updates; -payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true peer:InputPeer = payments.StarsRevenueStats; -payments.getStarsRevenueWithdrawalUrl#13bbe8b3 peer:InputPeer stars:long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; +payments.getStarsRevenueStats#d91ffad6 flags:# dark:flags.0?true ton:flags.1?true peer:InputPeer = payments.StarsRevenueStats; +payments.getStarsRevenueWithdrawalUrl#2433dc92 flags:# ton:flags.0?true peer:InputPeer amount:flags.1?long password:InputCheckPasswordSRP = payments.StarsRevenueWithdrawalUrl; payments.getStarsRevenueAdsAccountUrl#d1d7efc5 peer:InputPeer = payments.StarsRevenueAdsAccountUrl; -payments.getStarsTransactionsByID#27842d2e peer:InputPeer id:Vector = payments.StarsStatus; +payments.getStarsTransactionsByID#2dca16b8 flags:# ton:flags.0?true peer:InputPeer id:Vector = payments.StarsStatus; payments.getStarsGiftOptions#d3c96bc8 flags:# user_id:flags.0?InputUser = Vector; payments.getStarsSubscriptions#32512c5 flags:# missing_balance:flags.0?true peer:InputPeer offset:string = payments.StarsStatus; payments.changeStarsSubscription#c7770878 flags:# peer:InputPeer subscription_id:string canceled:flags.0?Bool = Bool; @@ -2676,9 +2673,6 @@ stats.getMessagePublicForwards#5f150144 channel:InputChannel msg_id:int offset:s stats.getMessageStats#b6e0a3f5 flags:# dark:flags.0?true channel:InputChannel msg_id:int = stats.MessageStats; stats.getStoryStats#374fef40 flags:# dark:flags.0?true peer:InputPeer id:int = stats.StoryStats; stats.getStoryPublicForwards#a6437ef6 peer:InputPeer id:int offset:string limit:int = stats.PublicForwards; -stats.getBroadcastRevenueStats#f788ee19 flags:# dark:flags.0?true peer:InputPeer = stats.BroadcastRevenueStats; -stats.getBroadcastRevenueWithdrawalUrl#9df4faad peer:InputPeer password:InputCheckPasswordSRP = stats.BroadcastRevenueWithdrawalUrl; -stats.getBroadcastRevenueTransactions#70990b6d peer:InputPeer offset:int limit:int = stats.BroadcastRevenueTransactions; chatlists.exportChatlistInvite#8472478e chatlist:InputChatlist title:string peers:Vector = chatlists.ExportedChatlistInvite; chatlists.deleteExportedInvite#719c5c5e chatlist:InputChatlist slug:string = Bool; @@ -2735,4 +2729,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; -// LAYER 205 +// LAYER 206 From 9d795911b4aa89cec6f565cb596b867ea6d1ff13 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Wed, 9 Jul 2025 18:47:45 +0700 Subject: [PATCH 29/39] pyrofork: Update API schema to Layer 207 Signed-off-by: wulan17 --- compiler/api/source/main_api.tl | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/api/source/main_api.tl b/compiler/api/source/main_api.tl index 9d8885db..a6fdb1bc 100644 --- a/compiler/api/source/main_api.tl +++ b/compiler/api/source/main_api.tl @@ -1899,11 +1899,11 @@ 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; -starGift#c62aca28 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 availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string = StarGift; -starGiftUnique#6411db89 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 availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long = StarGift; +starGift#7f853c12 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 availability_resale:flags.4?long convert_stars:long first_sale_date:flags.1?int last_sale_date:flags.1?int upgrade_stars:flags.3?long resell_min_stars:flags.4?long title:flags.5?string released_by:flags.6?Peer = StarGift; +starGiftUnique#f63778ae 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 availability_issued:int availability_total:int gift_address:flags.3?string resell_stars:flags.4?long released_by:flags.5?Peer = StarGift; payments.starGiftsNotModified#a388a368 = payments.StarGifts; -payments.starGifts#901689ea hash:int gifts:Vector = payments.StarGifts; +payments.starGifts#2ed82995 hash:int gifts:Vector chats:Vector users:Vector = payments.StarGifts; messageReportOption#7903e3d9 text:string option:bytes = MessageReportOption; @@ -2729,4 +2729,4 @@ smsjobs.finishJob#4f1ebf24 flags:# job_id:string error:flags.0?string = Bool; fragment.getCollectibleInfo#be1e85ba collectible:InputCollectible = fragment.CollectibleInfo; -// LAYER 206 +// LAYER 207 From 07bdefb0179e8d4db0a8af3cd5c81b7cc2a1f5f4 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Mon, 7 Jul 2025 19:30:03 +0700 Subject: [PATCH 30/39] pyrofork: Add todolist implementation Signed-off-by: wulan17 --- compiler/docs/compiler.py | 9 ++ pyrogram/enums/message_media_type.py | 3 + pyrogram/enums/message_service_type.py | 6 ++ pyrogram/methods/messages/__init__.py | 6 ++ pyrogram/methods/messages/add_task_to_todo.py | 82 +++++++++++++++ pyrogram/methods/messages/send_todo.py | 99 +++++++++++++++++++ .../messages/set_todo_tasks_completion.py | 76 ++++++++++++++ .../types/input_message_content/__init__.py | 4 +- .../input_message_content/input_todo_task.py | 37 +++++++ pyrogram/types/messages_and_media/__init__.py | 12 ++- pyrogram/types/messages_and_media/message.py | 63 ++++++++++++ .../types/messages_and_media/todo_list.py | 83 ++++++++++++++++ .../types/messages_and_media/todo_task.py | 85 ++++++++++++++++ .../messages_and_media/todo_tasks_added.py | 45 +++++++++ .../todo_tasks_completed.py | 44 +++++++++ .../todo_tasks_incompleted.py | 44 +++++++++ 16 files changed, 696 insertions(+), 2 deletions(-) create mode 100644 pyrogram/methods/messages/add_task_to_todo.py create mode 100644 pyrogram/methods/messages/send_todo.py create mode 100644 pyrogram/methods/messages/set_todo_tasks_completion.py create mode 100644 pyrogram/types/input_message_content/input_todo_task.py create mode 100644 pyrogram/types/messages_and_media/todo_list.py create mode 100644 pyrogram/types/messages_and_media/todo_task.py create mode 100644 pyrogram/types/messages_and_media/todo_tasks_added.py create mode 100644 pyrogram/types/messages_and_media/todo_tasks_completed.py create mode 100644 pyrogram/types/messages_and_media/todo_tasks_incompleted.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index 24eeb19f..f737c821 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -165,6 +165,7 @@ def pyrogram_api(): """, messages=""" Messages + add_task_to_todo send_message forward_media_group forward_messages @@ -174,6 +175,7 @@ def pyrogram_api(): send_audio send_document send_sticker + send_todo send_video send_animation send_voice @@ -185,6 +187,7 @@ def pyrogram_api(): send_contact send_cached_media send_reaction + set_todo_tasks_completion edit_message_text edit_message_caption edit_message_media @@ -535,6 +538,11 @@ def pyrogram_api(): MessageOrigin Photo Thumbnail + TodoList + TodoTask + TodoTasksAdded + TodoTasksCompleted + TodoTasksIncompleted Audio AvailableEffect Document @@ -734,6 +742,7 @@ def pyrogram_api(): InputVenueMessageContent InputContactMessageContent InputInvoiceMessageContent + InputTodoTask """, authorization=""" Authorization diff --git a/pyrogram/enums/message_media_type.py b/pyrogram/enums/message_media_type.py index c9e3fa44..067c2f96 100644 --- a/pyrogram/enums/message_media_type.py +++ b/pyrogram/enums/message_media_type.py @@ -84,3 +84,6 @@ class MessageMediaType(AutoName): PAID_MEDIA = auto() "Paid media" + + TODO = auto() + "To-Do list media" diff --git a/pyrogram/enums/message_service_type.py b/pyrogram/enums/message_service_type.py index 5f25dd6b..cd631b61 100644 --- a/pyrogram/enums/message_service_type.py +++ b/pyrogram/enums/message_service_type.py @@ -135,3 +135,9 @@ class MessageServiceType(AutoName): PAID_MESSAGE_PRICE_CHANGED = auto() "Paid message price changed" + + TODO_TASKS_ADDED = auto() + "To-Do tasks added" + + TODO_TASKS_COMPLETION = auto() + "To-Do tasks completion/incompletion" diff --git a/pyrogram/methods/messages/__init__.py b/pyrogram/methods/messages/__init__.py index d239cb49..8a720a87 100644 --- a/pyrogram/methods/messages/__init__.py +++ b/pyrogram/methods/messages/__init__.py @@ -17,6 +17,7 @@ # You should have received a copy of the GNU Lesser General Public License # along with Pyrofork. If not, see . +from .add_task_to_todo import AddTaskToTodo from .copy_media_group import CopyMediaGroup from .copy_message import CopyMessage from .delete_chat_history import DeleteChatHistory @@ -52,6 +53,7 @@ from .search_global_hashtag_messages import SearchGlobalHashtagMessages from .search_global_hashtag_messages_count import SearchGlobalHashtagMessagesCount from .search_messages import SearchMessages from .search_messages_count import SearchMessagesCount +from .set_todo_tasks_completion import SetTodoTasksCompletion from .send_animation import SendAnimation from .send_audio import SendAudio from .send_cached_media import SendCachedMedia @@ -66,6 +68,7 @@ from .send_photo import SendPhoto from .send_poll import SendPoll from .send_reaction import SendReaction from .send_sticker import SendSticker +from .send_todo import SendTodo from .send_venue import SendVenue from .send_video import SendVideo from .send_video_note import SendVideoNote @@ -79,6 +82,7 @@ from .transcribe_audio import TranscribeAudio from .translate_text import TranslateText class Messages( + AddTaskToTodo, DeleteChatHistory, DeleteMessages, DeleteScheduledMessages, @@ -93,6 +97,7 @@ class Messages( GetMessages, GetMessageReadParticipants, GetScheduledMessages, + SetTodoTasksCompletion, SendAudio, SendChatAction, SendContact, @@ -103,6 +108,7 @@ class Messages( SendMessage, SendPhoto, SendSticker, + SendTodo, SendVenue, SendVideo, SendVideoNote, diff --git a/pyrogram/methods/messages/add_task_to_todo.py b/pyrogram/methods/messages/add_task_to_todo.py new file mode 100644 index 00000000..a8203785 --- /dev/null +++ b/pyrogram/methods/messages/add_task_to_todo.py @@ -0,0 +1,82 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +import pyrogram + +from pyrogram import raw, types, utils +from typing import Union, List + + +class AddTaskToTodo: + async def add_task_to_todo( + self: "pyrogram.Client", + chat_id: Union[int, str], + message_id: Union[int, str], + tasks: List["types.InputTodoTask"], + parse_mode: str = None + ) -> "types.Message": + """Add tasks to a todo list. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target channel. + + message_id (``int`` | ``str``): + Unique identifier for the target message or username of the target channel. + + tasks (List of :obj:`~pyrogram.types.InputTodoTask`): + List of tasks to be added to the todo list. + + parse_mode (``str``, *optional*): + The parse mode to use for formatting the text. + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + Entities in the title of the todo list. + """ + tasks_list = [] + get_message = await self.get_messages(chat_id, message_id) + if not isinstance(get_message, types.Message): + raise ValueError("The message must be a valid Message object.") + todo_list = get_message.todo + last_task_id = max((task.id for task in todo_list.tasks), default=0) + for i, task in enumerate(tasks): + task_title, task_entities = (await utils.parse_text_entities(self, task.title, parse_mode, task.entities)).values() + tasks_list.append( + raw.types.TodoItem( + id=last_task_id + i + 1, + title=raw.types.TextWithEntities( + text=task_title, + entities=task_entities or [] + ) + ) + ) + + r = await self.invoke( + raw.functions.messages.AppendTodoList( + peer=await self.resolve_peer(chat_id), + msg_id=message_id, + list=tasks_list + ) + ) + + for update in r.updates: + if isinstance(update, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage, + raw.types.UpdateBotNewBusinessMessage)): + return types.Message._parse(self, update.message, update, r.users, r.chats) diff --git a/pyrogram/methods/messages/send_todo.py b/pyrogram/methods/messages/send_todo.py new file mode 100644 index 00000000..8e671085 --- /dev/null +++ b/pyrogram/methods/messages/send_todo.py @@ -0,0 +1,99 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +import pyrogram + +from pyrogram import raw, types, utils +from typing import Union, List + + +class SendTodo: + async def send_todo( + self: "pyrogram.Client", + chat_id: Union[int, str], + title: str, + tasks: List["types.InputTodoTask"], + entities: List["types.MessageEntity"] = None, + can_append: bool = False, + can_complete: bool = False, + parse_mode: Union[str, None] = None + ): + """Send a todo list to a chat. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier for the target chat or username of the target channel. + + title (``str``): + Title of the todo list. + + tasks (List of :obj:`~pyrogram.types.TodoTask`): + List of tasks in the todo list. + + entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + Entities in the title of the todo list. + + can_append (``bool``, *optional*): + True, if other users can append tasks to this todo list. + + can_complete (``bool``, *optional*): + True, if other users can complete tasks in this todo list. + """ + title, entities = (await utils.parse_text_entities(self, title, parse_mode, entities)).values() + tasks_list = [] + for i, task in enumerate(tasks): + task_title, task_entities = (await utils.parse_text_entities(self, task.title, parse_mode, task.entities)).values() + tasks_list.append( + raw.types.TodoItem( + id=i + 1, + title=raw.types.TextWithEntities( + text=task_title, + entities=task_entities or [] + ) + ) + ) + + r = await self.invoke( + raw.functions.messages.SendMedia( + peer=await self.resolve_peer(chat_id), + message="", + random_id=self.rnd_id(), + media=raw.types.InputMediaTodo( + todo=raw.types.TodoList( + title=raw.types.TextWithEntities( + text=title, + entities=entities or [] + ), + list=tasks_list, + others_can_append=can_append, + others_can_complete=can_complete + ) + ) + ) + ) + for i in r.updates: + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage, + raw.types.UpdateBotNewBusinessMessage)): + 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) + ) diff --git a/pyrogram/methods/messages/set_todo_tasks_completion.py b/pyrogram/methods/messages/set_todo_tasks_completion.py new file mode 100644 index 00000000..2bb0420b --- /dev/null +++ b/pyrogram/methods/messages/set_todo_tasks_completion.py @@ -0,0 +1,76 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +from typing import List, Union +from pyrogram import raw, types + + +class SetTodoTasksCompletion: + async def set_todo_tasks_completion( + self, + chat_id: int | str, + message_id: int, + completed_ids: Union[int, List[int]] = None, + incompleted_ids: Union[int, List[int]] = None + ) -> "types.Message": + """Set the completion status of one or more todo tasks. + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + + message_id (``int``): + Unique identifier of the message containing the todo list. + + completed_ids (``int`` | List of ``int``, *optional*): + Unique identifier of the todo tasks to be marked as completed. + If a list is provided, all tasks in the list will be marked as completed. + + incompleted_ids (``int`` | List of ``int``, *optional*): + Unique identifier of the todo tasks to be marked as incomplete. + If a list is provided, all tasks in the list will be marked as incomplete. + """ + is_complete_iterable = None + is_incomplete_iterable = None + if completed_ids: + is_complete_iterable = not isinstance(completed_ids, int) + if incompleted_ids: + is_incomplete_iterable = not isinstance(incompleted_ids, int) + if not is_complete_iterable and not is_incomplete_iterable: + raise ValueError("At least one of completed_ids or incompleted_ids must be provided.") + + r = await self.invoke( + raw.functions.messages.ToggleTodoCompleted( + peer=await self.resolve_peer(chat_id), + msg_id=message_id, + completed=(completed_ids if is_complete_iterable else [completed_ids]) if completed_ids else [], + incompleted=(incompleted_ids if is_incomplete_iterable else [incompleted_ids]) if incompleted_ids else [] + ) + ) + + for i in r.updates: + if isinstance(i, (raw.types.UpdateNewMessage, + raw.types.UpdateNewChannelMessage, + raw.types.UpdateNewScheduledMessage, + raw.types.UpdateBotNewBusinessMessage)): + 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) + ) diff --git a/pyrogram/types/input_message_content/__init__.py b/pyrogram/types/input_message_content/__init__.py index ae897b0d..5b2b15a0 100644 --- a/pyrogram/types/input_message_content/__init__.py +++ b/pyrogram/types/input_message_content/__init__.py @@ -26,6 +26,7 @@ from .input_location_message_content import InputLocationMessageContent from .input_venue_message_content import InputVenueMessageContent from .input_contact_message_content import InputContactMessageContent from .input_invoice_message_content import InputInvoiceMessageContent +from .input_todo_task import InputTodoTask __all__ = [ "InputMessageContent", @@ -36,5 +37,6 @@ __all__ = [ "InputLocationMessageContent", "InputVenueMessageContent", "InputContactMessageContent", - "InputInvoiceMessageContent" + "InputInvoiceMessageContent", + "InputTodoTask" ] diff --git a/pyrogram/types/input_message_content/input_todo_task.py b/pyrogram/types/input_message_content/input_todo_task.py new file mode 100644 index 00000000..2e4d6ab0 --- /dev/null +++ b/pyrogram/types/input_message_content/input_todo_task.py @@ -0,0 +1,37 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +from ..object import Object + + +class InputTodoTask(Object): + """Contains information about a todo task. + + Parameters: + title (``str``): + Title of the task. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + Entities in the title of the task. + """ + + def __init__(self, *, title: str, entities: list = None): + super().__init__() + + self.title = title + self.entities = entities diff --git a/pyrogram/types/messages_and_media/__init__.py b/pyrogram/types/messages_and_media/__init__.py index 7cb8837f..778ad9d9 100644 --- a/pyrogram/types/messages_and_media/__init__.py +++ b/pyrogram/types/messages_and_media/__init__.py @@ -55,6 +55,11 @@ from .stickerset import StickerSet from .stories_privacy_rules import StoriesPrivacyRules from .stripped_thumbnail import StrippedThumbnail from .thumbnail import Thumbnail +from .todo_list import TodoList +from .todo_task import TodoTask +from .todo_tasks_added import TodoTasksAdded +from .todo_tasks_completed import TodoTasksCompleted +from .todo_tasks_incompleted import TodoTasksIncompleted from .venue import Venue from .video import Video from .video_note import VideoNote @@ -142,5 +147,10 @@ __all__ = [ "WallpaperSettings", "TranscribedAudio", "TranslatedText", - "TextQuote" + "TextQuote", + "TodoList", + "TodoTask", + "TodoTasksAdded", + "TodoTasksCompleted", + "TodoTasksIncompleted" ] diff --git a/pyrogram/types/messages_and_media/message.py b/pyrogram/types/messages_and_media/message.py index bb6007c2..bf53a774 100644 --- a/pyrogram/types/messages_and_media/message.py +++ b/pyrogram/types/messages_and_media/message.py @@ -194,6 +194,9 @@ class Message(Object, Update): paid_media (:obj:`~pyrogram.types.PaidMedia`, *optional*): Message is a paid media, information about the paid media. + todo (:obj:`~pyrogram.types.Todo`, *optional*): + Message is a todo list, information about the todo list. + sticker (:obj:`~pyrogram.types.Sticker`, *optional*): Message is a sticker, information about the sticker. @@ -404,6 +407,21 @@ class Message(Object, Update): gifted_premium (:obj:`~pyrogram.types.GiftedPremium`, *optional*): Info about a gifted Telegram Premium subscription + screenshot_taken (:obj:`~pyrogram.types.ScreenshotTaken`, *optional*): + Service message: screenshot taken. + + paid_message_price_changed (:obj:`~pyrogram.types.PaidMessagePriceChanged`, *optional*): + Service message: paid message price changed. + + todo_tasks_added (:obj:`~pyrogram.types.TodoTasksAdded`, *optional*): + Service message: todo tasks added. + + todo_tasks_completed (:obj:`~pyrogram.types.TodoTasksCompleted`, *optional*): + Service message: todo tasks completed. + + todo_tasks_incompleted (:obj:`~pyrogram.types.TodoTasksIncompleted`, *optional*): + Service message: todo tasks incompleted. + link (``str``, *property*): Generate a link to this message, only for groups and channels. @@ -468,6 +486,7 @@ class Message(Object, Update): document: "types.Document" = None, photo: "types.Photo" = None, paid_media: "types.PaidMedia" = None, + todo: "types.Todo" = None, sticker: "types.Sticker" = None, animation: "types.Animation" = None, game: "types.Game" = None, @@ -481,6 +500,9 @@ class Message(Object, Update): gift: "types.Gift" = None, screenshot_taken: "types.ScreenshotTaken" = None, paid_message_price_changed: "types.PaidMessagePriceChanged" = None, + todo_tasks_added: "types.TodoTasksAdded" = None, + todo_tasks_completed: "types.TodoTasksCompleted" = None, + todo_tasks_incompleted: "types.TodoTasksIncompleted" = None, invoice: "types.Invoice" = None, story: Union["types.MessageStory", "types.Story"] = None, alternative_videos: List["types.AlternativeVideo"] = None, @@ -584,6 +606,7 @@ class Message(Object, Update): self.document = document self.photo = photo self.paid_media = paid_media + self.todo = todo self.sticker = sticker self.animation = animation self.game = game @@ -598,6 +621,9 @@ class Message(Object, Update): self.gift = gift self.screenshot_taken = screenshot_taken self.paid_message_price_changed = paid_message_price_changed + self.todo_tasks_added = todo_tasks_added + self.todo_tasks_completed = todo_tasks_completed + self.todo_tasks_incompleted = todo_tasks_incompleted self.invoice = invoice self.story = story self.video = video @@ -763,6 +789,9 @@ class Message(Object, Update): gift = None screenshot_taken = None paid_message_price_changed = None + todo_tasks_added = None + todo_tasks_completed = None + todo_tasks_incompleted = None service_type = None chat_join_type = None @@ -888,6 +917,7 @@ class Message(Object, Update): paid_message_price_changed = types.PaidMessagePriceChanged._parse(action) service_type = enums.MessageServiceType.PAID_MESSAGE_PRICE_CHANGED + parsed_message = Message( id=message.id, message_thread_id=message_thread_id, @@ -967,6 +997,34 @@ class Message(Object, Update): parsed_message.service = enums.MessageServiceType.GAME_HIGH_SCORE except MessageIdsEmpty: pass + if isinstance(action, raw.types.MessageActionTodoCompletions): + if action.completed: + parsed_message.todo_tasks_completed = types.TodoTasksCompleted._parse(action) + if action.incompleted: + parsed_message.todo_tasks_incompleted = types.TodoTasksIncompleted._parse(action) + parsed_message.service_type = enums.MessageServiceType.TODO_TASKS_COMPLETION + try: + parsed_message.reply_to_message = await client.get_messages( + parsed_message.chat.id, + reply_to_message_ids=message.id, + replies=0 + ) + except MessageIdsEmpty: + pass + parsed_message.reply_to_message_id = message.reply_to.reply_to_msg_id + + if isinstance(action, raw.types.MessageActionTodoAppendTasks): + parsed_message.todo_tasks_added = types.TodoTasksAdded._parse(client, action) + parsed_message.service = enums.MessageServiceType.TODO_TASKS_ADDED + try: + parsed_message.reply_to_message = await client.get_messages( + parsed_message.chat.id, + reply_to_message_ids=message.id, + replies=0 + ) + except MessageIdsEmpty: + pass + parsed_message.reply_to_message_id = message.reply_to.reply_to_msg_id client.message_cache[(parsed_message.chat.id, parsed_message.id)] = parsed_message @@ -1004,6 +1062,7 @@ class Message(Object, Update): photo = None paid_media = None + todo = None location = None contact = None venue = None @@ -1130,6 +1189,9 @@ class Message(Object, Update): elif isinstance(media, raw.types.MessageMediaPaidMedia): paid_media = types.PaidMedia._parse(client, media) media_type = enums.MessageMediaType.PAID_MEDIA + elif isinstance(media, raw.types.MessageMediaToDo): + todo = types.TodoList._parse(client, media, users) + media_type = enums.MessageMediaType.TODO else: media = None @@ -1199,6 +1261,7 @@ class Message(Object, Update): invert_media=message.invert_media, photo=photo, paid_media=paid_media, + todo=todo, location=location, contact=contact, venue=venue, diff --git a/pyrogram/types/messages_and_media/todo_list.py b/pyrogram/types/messages_and_media/todo_list.py new file mode 100644 index 00000000..5c30a4f0 --- /dev/null +++ b/pyrogram/types/messages_and_media/todo_list.py @@ -0,0 +1,83 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + + +from typing import List, Dict + +import pyrogram +from pyrogram import raw, types +from ..object import Object + + +class TodoList(Object): + """A list of tasks. + + Parameters: + title (``str``): + Title of the todo list. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + Entities in the title of the todo list. + + tasks (List of :obj:`~pyrogram.types.TodoTask`): + List of tasks in the todo list. + + can_append (``bool``, optional): + True, if other users can append tasks to this todo list. + + can_complete (``bool``, optional): + True, if other users can complete tasks in this todo list. + """ + + def __init__( + self, + title: str, + entities: List["types.MessageEntity"], + tasks: List["types.TodoTask"] = None, + can_append: bool = False, + can_complete: bool = False + ): + super().__init__() + + self.title = title + self.entities = entities + self.tasks = tasks + self.can_append = can_append + self.can_complete = can_complete + + @staticmethod + def _parse( + client: "pyrogram.Client", + todo: "raw.types.TodoList", + users: Dict + ) -> "TodoList": + todo_list = todo.todo + completions = todo.completions + entities = [types.MessageEntity._parse(client, entity, None) for entity in todo_list.title.entities] + entities = types.List(filter(lambda x: x is not None, entities)) + tasks = [ + types.TodoTask._parse(client, task, users, completions) + for task in todo_list.list + ] if todo_list.list else [] + return TodoList( + title=todo_list.title.text, + entities=entities, + tasks=tasks, + can_append=todo_list.others_can_append, + can_complete=todo_list.others_can_complete + ) diff --git a/pyrogram/types/messages_and_media/todo_task.py b/pyrogram/types/messages_and_media/todo_task.py new file mode 100644 index 00000000..01a7c97d --- /dev/null +++ b/pyrogram/types/messages_and_media/todo_task.py @@ -0,0 +1,85 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + + +from typing import List, Dict + +import pyrogram +from pyrogram import raw, types, utils +from ..object import Object + + +class TodoTask(Object): + """A task in a todo list. + + Parameters: + title (``str``): + Title of the task. + + entities (List of :obj:`~pyrogram.types.MessageEntity`): + Entities in the title of the task. + + is_completed (``bool``): + True, if the task is completed. + + completed_by (:obj:`~pyrogram.types.User`, *optional*): + User who completed the task. + + complete_date (:obj:`~datetime.datetime`, *optional*): + Date when the task was completed. + """ + + def __init__( + self, + id: int, + title: str, + entities: List["types.MessageEntity"], + is_completed: bool, + completed_by: "types.User" = None, + complete_date: "pyrogram.types.datetime" = None + ): + super().__init__() + + self.id = id + self.title = title + self.entities = entities + self.is_completed = is_completed + self.completed_by = completed_by + self.complete_date = complete_date + + @staticmethod + def _parse( + client: "pyrogram.Client", + todo_task: "raw.types.TodoTask", + users: Dict, + completions: List["raw.types.TodoTaskCompletion"] = None + ) -> "TodoTask": + entities = [types.MessageEntity._parse(client, entity, None) for entity in todo_task.title.entities] + entities = types.List(filter(lambda x: x is not None, entities)) + complete = {i.id: i for i in completions} if completions else {} + todo_completion = complete.get(todo_task.id) + completed_by = types.User._parse(client, users.get(todo_completion.completed_by, None)) if todo_completion else None + complete_date = utils.timestamp_to_datetime(todo_completion.date) if todo_completion else None + return TodoTask( + id=todo_task.id, + title=todo_task.title.text, + entities=entities, + is_completed=True if todo_completion else False, + completed_by=completed_by, + complete_date=complete_date + ) diff --git a/pyrogram/types/messages_and_media/todo_tasks_added.py b/pyrogram/types/messages_and_media/todo_tasks_added.py new file mode 100644 index 00000000..70da3bdd --- /dev/null +++ b/pyrogram/types/messages_and_media/todo_tasks_added.py @@ -0,0 +1,45 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +import pyrogram + +from pyrogram import raw, types +from ..object import Object + + +class TodoTasksAdded(Object): + """A todo task added to a todo list. + + Parameters: + task (:obj:`~pyrogram.types.TodoTask`): + The added todo task. + """ + + def __init__(self, tasks: "types.TodoTask"): + super().__init__() + + self.tasks = tasks + + @staticmethod + def _parse( + client: "pyrogram.Client", + todo_task_added: "raw.types.MessageActionTodoAppendTasks" + ) -> "TodoTasksAdded": + return TodoTasksAdded( + tasks=[types.TodoTask._parse(client, task, {}, {}) for task in todo_task_added.list] + ) diff --git a/pyrogram/types/messages_and_media/todo_tasks_completed.py b/pyrogram/types/messages_and_media/todo_tasks_completed.py new file mode 100644 index 00000000..4b0fdcb3 --- /dev/null +++ b/pyrogram/types/messages_and_media/todo_tasks_completed.py @@ -0,0 +1,44 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + + +from typing import List + +from pyrogram import raw +from ..object import Object + + +class TodoTasksCompleted(Object): + """One or more todo task/s has been flag as complete. + + Parameters: + ids (List of ``int``): + List of Unique identifier of the todo tasks. + """ + + def __init__(self, ids: List[int]): + super().__init__() + + self.ids = ids + + @staticmethod + def _parse(todo_completion: "raw.types.TodoCompletion") -> "TodoTasksCompleted": + ids = [id for id in todo_completion.completed] + return TodoTasksCompleted( + ids=ids, + ) diff --git a/pyrogram/types/messages_and_media/todo_tasks_incompleted.py b/pyrogram/types/messages_and_media/todo_tasks_incompleted.py new file mode 100644 index 00000000..e0a33762 --- /dev/null +++ b/pyrogram/types/messages_and_media/todo_tasks_incompleted.py @@ -0,0 +1,44 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + + +from typing import List + +from pyrogram import raw +from ..object import Object + + +class TodoTasksIncompleted(Object): + """One or more todo task/s has been flag as incomplete. + + Parameters: + ids (List of ``int``): + List of Unique identifier of the todo tasks. + """ + + def __init__(self, ids: List[int]): + super().__init__() + + self.ids = ids + + @staticmethod + def _parse(todo_completion: "raw.types.TodoCompletion") -> "TodoTasksIncompleted": + ids = [id for id in todo_completion.incompleted] + return TodoTasksIncompleted( + ids=ids, + ) From 621c690e553cc25dad2069a4db4b6790c4f6b9d5 Mon Sep 17 00:00:00 2001 From: Otazuki <115762083+Otazuki004@users.noreply.github.com> Date: Thu, 3 Jul 2025 12:25:03 +0530 Subject: [PATCH 31/39] pyrofork: Add transfer_chat_ownership method (#145) Signed-off-by: wulan17 --- compiler/docs/compiler.py | 1 + pyrogram/methods/chats/__init__.py | 2 + .../methods/chats/transfer_chat_ownership.py | 83 +++++++++++++++++++ 3 files changed, 86 insertions(+) create mode 100644 pyrogram/methods/chats/transfer_chat_ownership.py diff --git a/compiler/docs/compiler.py b/compiler/docs/compiler.py index f737c821..f262a6b3 100644 --- a/compiler/docs/compiler.py +++ b/compiler/docs/compiler.py @@ -285,6 +285,7 @@ def pyrogram_api(): hide_general_topic reopen_forum_topic reopen_general_topic + transfer_chat_ownership unhide_general_topic update_color update_folder diff --git a/pyrogram/methods/chats/__init__.py b/pyrogram/methods/chats/__init__.py index 267a05a9..4ec5fd10 100644 --- a/pyrogram/methods/chats/__init__.py +++ b/pyrogram/methods/chats/__init__.py @@ -67,6 +67,7 @@ from .set_chat_title import SetChatTitle from .set_chat_username import SetChatUsername from .set_send_as_chat import SetSendAsChat from .set_slow_mode import SetSlowMode +from .transfer_chat_ownership import TransferChatOwnership from .unarchive_chats import UnarchiveChats from .unban_chat_member import UnbanChatMember from .unpin_all_chat_messages import UnpinAllChatMessages @@ -130,6 +131,7 @@ class Chats( GetSendAsChats, SetSendAsChat, SetChatProtectedContent, + TransferChatOwnership, UpdateColor, UpdateFolder ): diff --git a/pyrogram/methods/chats/transfer_chat_ownership.py b/pyrogram/methods/chats/transfer_chat_ownership.py new file mode 100644 index 00000000..78b23ac2 --- /dev/null +++ b/pyrogram/methods/chats/transfer_chat_ownership.py @@ -0,0 +1,83 @@ +# Pyrofork - Telegram MTProto API Client Library for Python +# Copyright (C) 2022-present 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 . + +from typing import Union +import pyrogram +from pyrogram import raw, utils + + +class TransferChatOwnership: + async def transfer_chat_ownership( + self: "pyrogram.Client", + chat_id: Union[int, str], + user_id: Union[int, str], + password: str, + ) -> bool: + """Transfer the owner of a chat or channel to another user. + + .. note: + + Requires owner privileges. + + .. include:: /_includes/usable-by/users.rst + + Parameters: + chat_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the target chat. + Unique identifier for the target chat in form of a *t.me/joinchat/* link, identifier (int) or username + of the target channel/supergroup (in the format @username). + + user_id (``int`` | ``str``): + Unique identifier (int) or username (str) of the new owner. + For a contact that exists in your Telegram address book you can use his phone number (str). + + password (``str``): + The 2-step verification password of the current user. + + Returns: + ``bool``: True on success. + + Raises: + ValueError: In case of invalid parameters. + RPCError: In case of a Telegram RPC error. + + Example: + .. code-block:: python + + await app.transfer_chat_ownership(chat_id, user_id, "password") + """ + peer_channel = await self.resolve_peer(chat_id) + peer_user = await self.resolve_peer(user_id) + + if not isinstance(peer_channel, raw.types.InputPeerChannel): + raise ValueError("The chat_id must belong to a channel/supergroup.") + + if not isinstance(peer_user, raw.types.InputPeerUser): + raise ValueError("The user_id must belong to a user.") + + r = await self.invoke( + raw.functions.channels.EditCreator( + channel=peer_channel, + user_id=peer_user, + password=utils.compute_password_check( + await self.invoke(raw.functions.account.GetPassword()), password + ), + ) + ) + + return bool(r) From 9b670a78b3c6c4759b3e03bf14bcb63e24a6a9b4 Mon Sep 17 00:00:00 2001 From: Hentinel Date: Sat, 26 Apr 2025 05:48:05 +0300 Subject: [PATCH 32/39] pyrofork: Allow to specify system_lang_code and lang_pack (#129) Signed-off-by: wulan17 --- pyrogram/client.py | 6 ++++++ pyrogram/session/session.py | 4 ++-- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index 52b8aba0..e21414d4 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -227,6 +227,8 @@ class Client(Methods): SYSTEM_VERSION = f"{platform.system()} {platform.release()}" LANG_CODE = "en" + LANG_PACK = "" + SYSTEM_LANG_CODE = "en-US" PARENT_DIR = Path(sys.argv[0]).parent @@ -252,7 +254,9 @@ class Client(Methods): app_version: str = APP_VERSION, device_model: str = DEVICE_MODEL, system_version: str = SYSTEM_VERSION, + system_lang_code: str = SYSTEM_LANG_CODE, lang_code: str = LANG_CODE, + lang_pack: str = LANG_PACK, ipv6: Optional[bool] = False, alt_port: Optional[bool] = False, proxy: Optional[dict] = None, @@ -288,7 +292,9 @@ class Client(Methods): self.app_version = app_version self.device_model = device_model self.system_version = system_version + self.system_lang_code = system_lang_code.lower() self.lang_code = lang_code.lower() + self.lang_pack = lang_pack.lower() self.ipv6 = ipv6 self.alt_port = alt_port self.proxy = proxy diff --git a/pyrogram/session/session.py b/pyrogram/session/session.py index c84a3cb4..87d57409 100644 --- a/pyrogram/session/session.py +++ b/pyrogram/session/session.py @@ -131,9 +131,9 @@ class Session: app_version=self.client.app_version, device_model=self.client.device_model, system_version=self.client.system_version, - system_lang_code=self.client.lang_code, + system_lang_code=self.client.system_lang_code, lang_code=self.client.lang_code, - lang_pack="", + lang_pack=self.client.lang_pack, query=raw.functions.help.GetConfig(), ) ), From c8b22bb5e752dfb57cd5fb842c397191b2dccd73 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Wed, 9 Jul 2025 18:59:28 +0700 Subject: [PATCH 33/39] pyrofork: Add resale_amount field to Gift (#144) Signed-off-by: wulan17 --- pyrogram/types/payments/gift.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/pyrogram/types/payments/gift.py b/pyrogram/types/payments/gift.py index 2af51f66..0e26e691 100644 --- a/pyrogram/types/payments/gift.py +++ b/pyrogram/types/payments/gift.py @@ -104,6 +104,10 @@ class Gift(Object): The number of gifts available for purchase. Returned only if is_limited is True. + resale_amount (``int``, *optional*): + The number of gifts available for resale. + Returned only if is_limited is True. + total_amount (``int``, *optional*): Total amount of gifts. Returned only if is_limited is True. @@ -177,6 +181,7 @@ class Gift(Object): collectible_id: Optional[int] = None, attributes: Optional[List["types.GiftAttribute"]] = None, available_amount: Optional[int] = None, + resale_amount: Optional[int] = None, total_amount: Optional[int] = None, can_upgrade: Optional[bool] = None, can_export_at: Optional[datetime] = None, @@ -216,6 +221,7 @@ class Gift(Object): self.collectible_id = collectible_id self.attributes = attributes self.available_amount = available_amount + self.resale_amount = resale_amount self.total_amount = total_amount self.can_upgrade = can_upgrade self.can_export_at = can_export_at @@ -254,6 +260,7 @@ class Gift(Object): convert_price=star_gift.convert_stars, upgrade_price=getattr(star_gift, "upgrade_stars", None), available_amount=getattr(star_gift, "availability_remains", None), + resale_amount=getattr(star_gift, "availability_resale", None), total_amount=getattr(star_gift, "availability_total", None), is_limited=getattr(star_gift, "limited", None), is_sold_out=getattr(star_gift, "sold_out", None), @@ -281,6 +288,7 @@ class Gift(Object): [await types.GiftAttribute._parse(client, attr, users) for attr in star_gift.attributes] ) or None, available_amount=getattr(star_gift, "availability_issued", None), + resale_amount=getattr(star_gift, "availability_resale", None), total_amount=getattr(star_gift, "availability_total", None), owner=( types.Chat._parse_chat(client, users.get(owner_id) or From 46e755f297068e45b08f00aaa6a79bdac633c2a2 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Wed, 9 Jul 2025 21:39:46 +0700 Subject: [PATCH 34/39] pyrofork: client: fix looping prompt when use `qrcode` as input Signed-off-by: wulan17 --- pyrogram/client.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/pyrogram/client.py b/pyrogram/client.py index e21414d4..dfb3e07f 100644 --- a/pyrogram/client.py +++ b/pyrogram/client.py @@ -451,25 +451,25 @@ class Client(Methods): return await self.sign_in_bot(value) else: self.phone_number = value - - sent_code = await self.send_code(self.phone_number) + if not self.use_qrcode: + sent_code = await self.send_code(self.phone_number) except BadRequest as e: print(e.MESSAGE) self.phone_number = None self.bot_token = None else: break + if not self.use_qrcode: + sent_code_descriptions = { + enums.SentCodeType.APP: "Telegram app", + enums.SentCodeType.SMS: "SMS", + enums.SentCodeType.CALL: "phone call", + enums.SentCodeType.FLASH_CALL: "phone flash call", + enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS", + enums.SentCodeType.EMAIL_CODE: "email code" + } - sent_code_descriptions = { - enums.SentCodeType.APP: "Telegram app", - enums.SentCodeType.SMS: "SMS", - enums.SentCodeType.CALL: "phone call", - enums.SentCodeType.FLASH_CALL: "phone flash call", - enums.SentCodeType.FRAGMENT_SMS: "Fragment SMS", - enums.SentCodeType.EMAIL_CODE: "email code" - } - - print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}") + print(f"The confirmation code has been sent via {sent_code_descriptions[sent_code.type]}") while True: if not self.use_qrcode and not self.phone_code: From 4a109b3dc26cf483773d13f206e30a697f391b69 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Thu, 10 Jul 2025 19:06:17 +0700 Subject: [PATCH 35/39] pyrofork: Adapt filters.linked_channel to latest changes Signed-off-by: wulan17 --- pyrogram/filters.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/filters.py b/pyrogram/filters.py index a5f97560..5bb098a8 100644 --- a/pyrogram/filters.py +++ b/pyrogram/filters.py @@ -796,7 +796,7 @@ from_scheduled = create(from_scheduled_filter) # region linked_channel_filter async def linked_channel_filter(_, __, m: Message): - return bool(m.forward_from_chat and not m.from_user) + return bool((m.forward_origin and m.forward_origin.chat) and not m.from_user) linked_channel = create(linked_channel_filter) From 413556a3f29ea1fd649ed07ef85ba13158e6c85a Mon Sep 17 00:00:00 2001 From: wulan17 Date: Thu, 10 Jul 2025 19:21:36 +0700 Subject: [PATCH 36/39] pyrofork: Refactor folders Signed-off-by: wulan17 --- pyrogram/methods/chats/get_folders.py | 2 +- pyrogram/methods/chats/update_folder.py | 22 +++++++++++++++++----- pyrogram/types/user_and_chats/folder.py | 11 ++++++++++- 3 files changed, 28 insertions(+), 7 deletions(-) diff --git a/pyrogram/methods/chats/get_folders.py b/pyrogram/methods/chats/get_folders.py index cadfec50..6782f896 100644 --- a/pyrogram/methods/chats/get_folders.py +++ b/pyrogram/methods/chats/get_folders.py @@ -81,7 +81,7 @@ class GetFolders: users.update({i.id: i for i in r.users}) chats.update({i.id: i for i in r.chats}) - folders = types.List(types.Folder._parse(self, folder, users, chats) for folder in raw_folders) + folders = types.List([types.Folder._parse(self, folder, users, chats) for folder in raw_folders]) if not folders: return None diff --git a/pyrogram/methods/chats/update_folder.py b/pyrogram/methods/chats/update_folder.py index a641fb99..37e1eb2a 100644 --- a/pyrogram/methods/chats/update_folder.py +++ b/pyrogram/methods/chats/update_folder.py @@ -20,8 +20,7 @@ from typing import List, Union import pyrogram -from pyrogram import raw -from pyrogram import enums +from pyrogram import enums, raw, types, utils class UpdateFolder: @@ -29,6 +28,7 @@ class UpdateFolder: self: "pyrogram.Client", folder_id: int, title: str, + title_entities: List["types.MessageEntity"] = None, included_chats: Union[Union[int, str], List[Union[int, str]]] = None, excluded_chats: Union[Union[int, str], List[Union[int, str]]] = None, pinned_chats: Union[Union[int, str], List[Union[int, str]]] = None, @@ -41,7 +41,8 @@ class UpdateFolder: exclude_read: bool = None, exclude_archived: bool = None, color: "enums.FolderColor" = None, - emoji: str = None + emoji: str = None, + parse_mode: "pyrogram.enums.ParseMode" = pyrogram.enums.ParseMode.DEFAULT ) -> bool: """Create or update a user's folder. @@ -54,6 +55,9 @@ class UpdateFolder: title (``str``): Folder title. + title_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + Entities for the folder title. + included_chats (``int`` | ``str`` | List of ``int`` or ``str``, *optional*): Users or chats that should added in the folder You can pass an ID (int), username (str) or phone number (str). @@ -98,6 +102,9 @@ class UpdateFolder: Color type. Pass :obj:`~pyrogram.enums.FolderColor` to set folder color. + parse_mode (:obj:`~pyrogram.enums.ParseMode`, *optional*): + The parse mode to use for the title. + Returns: ``bool``: True, on success. @@ -107,6 +114,8 @@ class UpdateFolder: # Create or update folder app.update_folder(folder_id, title="New folder", included_chats="me") """ + title_text, title_entities = (await utils.parse_text_entities(self, title, parse_mode, title_entities)).values() + if not isinstance(included_chats, list): included_chats = [included_chats] if included_chats else [] if not isinstance(excluded_chats, list): @@ -119,7 +128,10 @@ class UpdateFolder: id=folder_id, filter=raw.types.DialogFilter( id=folder_id, - title=title, + title=raw.types.TextWithEntities( + text=title_text, + entities=title_entities or [] + ), pinned_peers=[ await self.resolve_peer(user_id) for user_id in pinned_chats @@ -146,4 +158,4 @@ class UpdateFolder: ) ) - return r + return bool(r) diff --git a/pyrogram/types/user_and_chats/folder.py b/pyrogram/types/user_and_chats/folder.py index 85f9bec6..50a0299f 100644 --- a/pyrogram/types/user_and_chats/folder.py +++ b/pyrogram/types/user_and_chats/folder.py @@ -37,6 +37,9 @@ class Folder(Object): title (``str``): The folder title. + title_entities (List of :obj:`~pyrogram.types.MessageEntity`, *optional*): + A list of entities in the folder title. + included_chats (List of :obj:`~pyrogram.types.Chat`, *optional*): A list of included chats in folder. @@ -83,6 +86,7 @@ class Folder(Object): client: "pyrogram.Client" = None, id: int, title: str, + title_entities: List["types.MessageEntity"] = None, included_chats: List["types.Chat"] = None, excluded_chats: List["types.Chat"] = None, pinned_chats: List["types.Chat"] = None, @@ -102,6 +106,7 @@ class Folder(Object): self.id = id self.title = title + self.title_entities = title_entities self.included_chats = included_chats self.excluded_chats = excluded_chats self.pinned_chats = pinned_chats @@ -122,6 +127,9 @@ class Folder(Object): included_chats = [] excluded_chats = [] pinned_chats = [] + title = folder.title + title_text = title.text + title_entities = [types.MessageEntity._parse(client, entity) for entity in title.entities] if title.entities else None for peer in folder.include_peers: try: @@ -144,7 +152,8 @@ class Folder(Object): return Folder( id=folder.id, - title=folder.title, + title=title_text, + title_entities=title_entities, included_chats=types.List(included_chats) or None, excluded_chats=types.List(excluded_chats) or None, pinned_chats=types.List(pinned_chats) or None, From 8acc4574586edea6be4ba845d7c99f74c2f911a2 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Thu, 10 Jul 2025 19:33:37 +0700 Subject: [PATCH 37/39] pyrofork: types: Chat: _parse_dialog: Handle InputPeerUser and InputPeerChat Signed-off-by: wulan17 --- pyrogram/types/user_and_chats/chat.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pyrogram/types/user_and_chats/chat.py b/pyrogram/types/user_and_chats/chat.py index cd42e983..3786f212 100644 --- a/pyrogram/types/user_and_chats/chat.py +++ b/pyrogram/types/user_and_chats/chat.py @@ -476,9 +476,9 @@ class Chat(Object): users: Dict[int, "raw.types.User"], chats: Dict[int, "raw.types.Chat"] ) -> "Chat": - if isinstance(peer, raw.types.PeerUser): + if isinstance(peer, raw.types.PeerUser) or isinstance(peer, raw.types.InputPeerUser): return Chat._parse_user_chat(client, users[peer.user_id]) - elif isinstance(peer, raw.types.PeerChat): + elif isinstance(peer, raw.types.PeerChat) or isinstance(peer, raw.types.InputPeerChat): return Chat._parse_chat_chat(client, chats[peer.chat_id]) else: return Chat._parse_channel_chat(client, chats[peer.channel_id]) From cf6141feb41b0bd49559dc8390d853ae39462d27 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Thu, 10 Jul 2025 19:58:10 +0700 Subject: [PATCH 38/39] pyrofork: Bump version to 2.3.68 Signed-off-by: wulan17 --- pyrogram/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyrogram/__init__.py b/pyrogram/__init__.py index 915319c5..30742d3a 100644 --- a/pyrogram/__init__.py +++ b/pyrogram/__init__.py @@ -18,7 +18,7 @@ # along with Pyrofork. If not, see . __fork_name__ = "PyroFork" -__version__ = "2.3.67" +__version__ = "2.3.68" __license__ = "GNU Lesser General Public License v3.0 (LGPL-3.0)" __copyright__ = "Copyright (C) 2022-present Mayuri-Chan " From cb38d6a02b3d364d384cf18b7109e1c51c43d494 Mon Sep 17 00:00:00 2001 From: wulan17 Date: Fri, 11 Jul 2025 20:31:21 +0700 Subject: [PATCH 39/39] pyrofork: docs: storage: Add example for official async mongodb driver Signed-off-by: wulan17 --- docs/source/topics/storage-engines.rst | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/docs/source/topics/storage-engines.rst b/docs/source/topics/storage-engines.rst index 4b89e31e..3fa29c46 100644 --- a/docs/source/topics/storage-engines.rst +++ b/docs/source/topics/storage-engines.rst @@ -80,7 +80,20 @@ Using async_pymongo (Recommended for python3.9+): print(await app.get_me()) -Using motor: +Using official mongodb driver: + +.. code-block:: python + + from pymongo import AsyncMongoClient + from pyrogram import Client + + conn = AsyncMongoClient("mongodb://...") + + async with Client("my_account", mongodb=dict(connection=conn, remove_peers=False)) as app: + print(await app.get_me()) + + +Using motor (Deprecated, but still works): .. code-block:: python