diff --git a/.github/workflows/autolock.yml b/.github/workflows/autolock.yml index 9c86508..0bd8a20 100644 --- a/.github/workflows/autolock.yml +++ b/.github/workflows/autolock.yml @@ -17,7 +17,7 @@ jobs: action: runs-on: ubuntu-latest steps: - - uses: dessant/lock-threads@v5.0.1 + - uses: dessant/lock-threads@v5 with: issue-inactive-days: '60' pr-inactive-days: '60' diff --git a/EXAMPLES.md b/EXAMPLES.md index 6fb7ee1..e32e10d 100644 --- a/EXAMPLES.md +++ b/EXAMPLES.md @@ -257,10 +257,10 @@ var history = await client.Messages_GetHistory(from_chat, limit: 1); var msg = history.Messages[0] as Message; // last message of source chat // • Forward the message (only the source message id is necessary) -await client.Messages_ForwardMessages(from_chat, new[] { msg.ID }, new[] { WTelegram.Helpers.RandomLong() }, to_chat); +await client.ForwardMessagesAsync(from_chat, [msg.ID], to_chat); // • Copy the message without the "Forwarded" header (only the source message id is necessary) -await client.Messages_ForwardMessages(from_chat, new[] { msg.ID }, new[] { WTelegram.Helpers.RandomLong() }, to_chat, drop_author: true); +await client.ForwardMessagesAsync(from_chat, [msg.ID], to_chat, drop_author: true); // • Alternative solution to copy the message (the full message is needed) await client.SendMessageAsync(to_chat, msg.message, msg.media?.ToInputMedia(), entities: msg.entities); @@ -544,7 +544,7 @@ using var client = new WTelegram.Client(Environment.GetEnvironmentVariable); client.MTProxyUrl = "https://t.me/proxy?server=...&port=...&secret=..."; await client.LoginUserIfNeeded(); ``` -You can find a list of working MTProxies in channels like [@ProxyMTProto](https://t.me/ProxyMTProto) or [@MTProxyT](https://t.me/MTProxyT) *(right-click the "Connect" buttons)* +You can find a list of working MTProxies in channels like [@ProxyMTProto](https://t.me/s/ProxyMTProto) or [@MTProxyT](https://t.me/s/MTProxyT) *(right-click the "Connect" buttons)* If your Telegram client is already connected to such MTPROTO proxy, you can also export its URL by clicking on the shield button ![🛡](https://raw.githubusercontent.com/telegramdesktop/tdesktop/dev/Telegram/Resources/icons/proxy_on.png) and then **⋮** > **Share** *Note: WTelegramClient always uses transport obfuscation when connecting to Telegram servers, even without MTProxy* diff --git a/src/Client.Helpers.cs b/src/Client.Helpers.cs index a3c55c4..c5891a5 100644 --- a/src/Client.Helpers.cs +++ b/src/Client.Helpers.cs @@ -19,14 +19,14 @@ partial class Client /// total size of file in bytes, or 0 if unknown public delegate void ProgressCallback(long transmitted, long totalSize); - /// Helper function to upload a file to Telegram + /// Helper method to upload a file to Telegram /// Path to the file to upload /// (optional) Callback for tracking the progression of the transfer /// an or than can be used in various requests public Task UploadFileAsync(string pathname, ProgressCallback progress = null) => UploadFileAsync(File.OpenRead(pathname), Path.GetFileName(pathname), progress); - /// Helper function to upload a file to Telegram + /// Helper method to upload a file to Telegram /// Content of the file to upload. This method close/dispose the stream /// Name of the file /// (optional) Callback for tracking the progression of the transfer @@ -107,7 +107,7 @@ async Task SavePart(int file_part, byte[] bytes) public Task Messages_SearchGlobal(string text = null, int offset_id = 0, int limit = int.MaxValue) where T : MessagesFilter, new() => this.Messages_SearchGlobal(text, new T(), offset_id: offset_id, limit: limit); - /// Helper function to send a media message more easily + /// Helper method to send a media message more easily /// Destination of message (chat group, channel, user chat, etc..) /// Caption for the media (in plain text) or /// Media file already uploaded to TG (see UploadFileAsync) @@ -137,7 +137,7 @@ public Task SendMediaAsync(InputPeer peer, string caption, InputFileBas } public enum LinkPreview { Disabled = 0, BelowText = 1, AboveText = 2 }; - /// Helper function to send a text or media message easily + /// Helper method to send a text or media message easily /// Destination of message (chat group, channel, user chat, etc..) /// The plain text of the message (or media caption) /// An instance of InputMedia-derived class, or if there is no associated media @@ -179,7 +179,7 @@ public async Task SendMessageAsync(InputPeer peer, string text, InputMe return null; } - /// Helper function to send an album (media group) of photos or documents more easily + /// Helper method to send an album (media group) of photos or documents more easily /// Destination of message (chat group, channel, user chat, etc..) /// An array or List of InputMedia-derived class /// Caption for the media (in plain text) or @@ -187,7 +187,7 @@ public async Task SendMessageAsync(InputPeer peer, string text, InputMe /// Text formatting entities for the caption. You can use MarkdownToEntities to create these /// UTC timestamp when the message should be sent /// Any URL pointing to a video should be considered as non-streamable - /// The media group messages as received by Telegram + /// The media group messages, as received by Telegram /// /// * The caption/entities are set on the first media
/// * and are supported natively for bot accounts, and for user accounts by downloading the file from the web via HttpClient and sending it to Telegram. @@ -280,6 +280,33 @@ async Task UploadFromUrl(string url) return result; } + /// Helper method to forwards messages more easily by their IDs. + /// Whether to forward messages without quoting the original author + /// Whether to strip captions from media + /// Source of messages + /// IDs of messages + /// Destination peer + /// Destination forum topic + /// The resulting forwarded messages, as received by Telegram + public async Task ForwardMessagesAsync(InputPeer from_peer, int[] msg_ids, InputPeer to_peer, int? top_msg_id = null, bool drop_author = false, bool drop_media_captions = false) + { + var random_id = Helpers.RandomLong(); + var random_ids = Enumerable.Range(0, msg_ids.Length).Select(i => random_id + i).ToArray(); + var updates = await this.Messages_ForwardMessages(from_peer, msg_ids, random_ids, to_peer, top_msg_id, drop_author: drop_author, drop_media_captions: drop_media_captions); + var msgIds = new int[updates.UpdateList.OfType().Count()]; + var result = new Message[msgIds.Length]; + foreach (var update in updates.UpdateList) + { + switch (update) + { + case UpdateMessageID updMsgId: msgIds[updMsgId.random_id - random_id] = updMsgId.id; break; + case UpdateNewMessage { message: Message message }: result[Array.IndexOf(msgIds, message.id)] = message; break; + case UpdateNewScheduledMessage { message: Message schedMsg }: result[Array.IndexOf(msgIds, schedMsg.id)] = schedMsg; break; + } + } + return result; + } + private Peer InputToPeer(InputPeer peer) => peer switch { InputPeerSelf => new PeerUser { user_id = _session.UserId },