diff --git a/src/Client.Helpers.cs b/src/Client.Helpers.cs index ab45b4e..57f4701 100644 --- a/src/Client.Helpers.cs +++ b/src/Client.Helpers.cs @@ -110,27 +110,30 @@ namespace WTelegram /// Helper function 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) - /// for automatic detection, "photo" for an inline photo, or a MIME type to send as a document + /// Media file already uploaded to TG (see UploadFileAsync) + /// for automatic detection, "photo" for an inline photo, "video" for a streamable MP4 video, or a MIME type to send as a document /// Your message is a reply to an existing message with this ID, in the same chat /// Text formatting entities for the caption. You can use MarkdownToEntities to create these /// UTC timestamp when the message should be sent /// The transmitted message confirmed by Telegram - public Task SendMediaAsync(InputPeer peer, string caption, InputFileBase mediaFile, string mimeType = null, int reply_to_msg_id = 0, MessageEntity[] entities = null, DateTime schedule_date = default) + public Task SendMediaAsync(InputPeer peer, string caption, InputFileBase uploadedFile, string mimeType = null, int reply_to_msg_id = 0, MessageEntity[] entities = null, DateTime schedule_date = default) { - mimeType ??= Path.GetExtension(mediaFile.Name)?.ToLowerInvariant() switch + mimeType ??= Path.GetExtension(uploadedFile.Name)?.ToLowerInvariant() switch { ".jpg" or ".jpeg" or ".png" or ".bmp" => "photo", + ".mp4" => "video", ".gif" => "image/gif", ".webp" => "image/webp", - ".mp4" => "video/mp4", ".mp3" => "audio/mpeg", ".wav" => "audio/x-wav", _ => "", // send as generic document with undefined MIME type }; if (mimeType == "photo") - return SendMessageAsync(peer, caption, new InputMediaUploadedPhoto { file = mediaFile }, reply_to_msg_id, entities, schedule_date); - return SendMessageAsync(peer, caption, new InputMediaUploadedDocument(mediaFile, mimeType), reply_to_msg_id, entities, schedule_date); + return SendMessageAsync(peer, caption, new InputMediaUploadedPhoto { file = uploadedFile }, reply_to_msg_id, entities, schedule_date); + else if (mimeType == "video") + return SendMessageAsync(peer, caption, new InputMediaUploadedDocument(uploadedFile, "video/mp4", new DocumentAttributeVideo { flags = DocumentAttributeVideo.Flags.supports_streaming }), reply_to_msg_id, entities, schedule_date); + else + return SendMessageAsync(peer, caption, new InputMediaUploadedDocument(uploadedFile, mimeType), reply_to_msg_id, entities, schedule_date); } public enum LinkPreview { Disabled = 0, BelowText = 1, AboveText = 2 }; @@ -184,6 +187,7 @@ namespace WTelegram /// Your message is a reply to an existing message with this ID, in the same chat /// 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 last of the media group messages, confirmed by Telegram /// /// * The caption/entities are set on the last media
@@ -191,7 +195,7 @@ namespace WTelegram /// WTelegramClient proxy settings don't apply to HttpClient
/// * You may run into errors if you mix, in the same album, photos and file documents having no thumbnails/video attributes ///
- public async Task SendAlbumAsync(InputPeer peer, ICollection medias, string caption = null, int reply_to_msg_id = 0, MessageEntity[] entities = null, DateTime schedule_date = default) + public async Task SendAlbumAsync(InputPeer peer, ICollection medias, string caption = null, int reply_to_msg_id = 0, MessageEntity[] entities = null, DateTime schedule_date = default, bool videoUrlAsFile = false) { System.Net.Http.HttpClient httpClient = null; int i = 0, length = medias.Count; @@ -215,7 +219,10 @@ namespace WTelegram case InputMediaDocumentExternal imde: string mimeType = null; var inputFile = await UploadFromUrl(imde.url); - ism.media = new InputMediaUploadedDocument(inputFile, mimeType); + if (mimeType?.StartsWith("video/") == true) + ism.media = new InputMediaUploadedDocument(inputFile, mimeType, new DocumentAttributeVideo { flags = DocumentAttributeVideo.Flags.supports_streaming }); + else + ism.media = new InputMediaUploadedDocument(inputFile, mimeType); goto retry; case InputMediaPhotoExternal impe: inputFile = await UploadFromUrl(impe.url); @@ -226,18 +233,14 @@ namespace WTelegram { var filename = Path.GetFileName(new Uri(url).LocalPath); httpClient ??= new(); - var response = await httpClient.GetAsync(url); + using var response = await httpClient.GetAsync(url, System.Net.Http.HttpCompletionOption.ResponseHeadersRead); + response.EnsureSuccessStatusCode(); using var stream = await response.Content.ReadAsStreamAsync(); mimeType = response.Content.Headers.ContentType?.MediaType; if (response.Content.Headers.ContentLength is long length) return await UploadFileAsync(new Helpers.IndirectStream(stream) { ContentLength = length }, filename); else - { - using var ms = new MemoryStream(); - await stream.CopyToAsync(ms); - ms.Position = 0; - return await UploadFileAsync(ms, filename); - } + return await UploadFileAsync(stream, filename); } } } diff --git a/src/TL.Helpers.cs b/src/TL.Helpers.cs index 746a734..8d2636c 100644 --- a/src/TL.Helpers.cs +++ b/src/TL.Helpers.cs @@ -107,6 +107,15 @@ namespace TL mime_type = mimeType; if (inputFile.Name is string filename) attributes = new[] { new DocumentAttributeFilename { file_name = filename } }; } + public InputMediaUploadedDocument(InputFileBase inputFile, string mimeType, params DocumentAttribute[] attribs) + { + file = inputFile; + mime_type = mimeType; + if (inputFile.Name is string filename && !attribs.Any(a => a is DocumentAttributeFilename)) + attributes = attribs.Append(new DocumentAttributeFilename { file_name = filename }).ToArray(); + else + attributes = attribs; + } } partial class InputPhoto