diff --git a/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs b/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs index 7d7f6a4630..57bb8ba262 100644 --- a/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs +++ b/src/Discord.Net.Core/Entities/Messages/FileAttachment.cs @@ -27,6 +27,16 @@ public struct FileAttachment : IDisposable /// public bool IsThumbnail { get; set; } + /// + /// Gets or sets the duration of a voice message. if the attachment is not a voice message. + /// + public double? DurationSeconds { get; set; } + + /// + /// Gets or sets bytearray representing a sampled waveform. if the attachment is not a voice message. + /// + public byte[] Waveform { get; set; } + #pragma warning disable IDISP008 /// /// Gets the stream containing the file content. @@ -44,7 +54,7 @@ public struct FileAttachment : IDisposable /// The description of the attachment. /// Whether or not the attachment is a spoiler. /// Whether or not this attachment should be a thumbnail for a media channel post. - public FileAttachment(Stream stream, string fileName, string description = null, bool isSpoiler = false, bool isThumbnail = false) + public FileAttachment(Stream stream, string fileName, string description = null, bool isSpoiler = false, bool isThumbnail = false, double? durationSeconds = null, byte[] waveform = null) { _isDisposed = false; FileName = fileName; @@ -57,6 +67,8 @@ public FileAttachment(Stream stream, string fileName, string description = null, } catch { } IsSpoiler = isSpoiler; + DurationSeconds = durationSeconds; + Waveform = waveform; } /// @@ -91,7 +103,7 @@ public FileAttachment(Stream stream, string fileName, string description = null, /// The file specified in was not found. /// /// An I/O error occurred while opening the file. - public FileAttachment(string path, string fileName = null, string description = null, bool isSpoiler = false, bool isThumbnail = false) + public FileAttachment(string path, string fileName = null, string description = null, bool isSpoiler = false, bool isThumbnail = false, double? durationSeconds = null, byte[] waveform = null) { _isDisposed = false; Stream = File.OpenRead(path); @@ -99,6 +111,8 @@ public FileAttachment(string path, string fileName = null, string description = Description = description; IsSpoiler = isSpoiler; IsThumbnail = isThumbnail; + DurationSeconds = durationSeconds; + Waveform = waveform; } public void Dispose() diff --git a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs index 591c9586bf..65bf93e087 100644 --- a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs +++ b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs @@ -76,6 +76,11 @@ public interface IAttachment : ISnowflakeEntity /// public string Waveform { get; } + /// + /// Gets the bytearray representing a sampled waveform. if the attachment is not a voice message. + /// + public byte[] WaveformBytes { get; } + /// /// Gets flags related to this to this attachment. /// diff --git a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs index 49a8268d7b..c1e4309eed 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadFileParams.cs @@ -1,6 +1,7 @@ using Discord.Net.Converters; using Discord.Net.Rest; using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.IO; using System.Linq; @@ -34,6 +35,9 @@ public IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); + if (Files.Any(x => x.Waveform is not null && x.DurationSeconds is not null)) + Flags = Flags.GetValueOrDefault(MessageFlags.None) | MessageFlags.VoiceMessage; + var payload = new Dictionary(); if (Content.IsSpecified) payload["content"] = Content.Value; @@ -71,7 +75,11 @@ public IReadOnlyDictionary ToDictionary() { id = (ulong)n, filename = filename, - description = attachment.Description ?? Optional.Unspecified + description = attachment.Description ?? Optional.Unspecified, + duration_secs = attachment.DurationSeconds ?? Optional.Unspecified, + waveform = attachment.Waveform is null + ? Optional.Unspecified + : Convert.ToBase64String(attachment.Waveform) }); } diff --git a/src/Discord.Net.Rest/API/Rest/UploadInteractionFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadInteractionFileParams.cs index 9ba1001644..dcdc7e65a8 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadInteractionFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadInteractionFileParams.cs @@ -44,6 +44,8 @@ public IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); + if (Files.Any(x => x.Waveform is not null && x.DurationSeconds is not null)) + Flags = Flags.GetValueOrDefault(MessageFlags.None) | MessageFlags.VoiceMessage; var payload = new Dictionary(); payload["type"] = Type; @@ -79,7 +81,11 @@ public IReadOnlyDictionary ToDictionary() { id = (ulong)n, filename = filename, - description = attachment.Description ?? Optional.Unspecified + description = attachment.Description ?? Optional.Unspecified, + duration_secs = attachment.DurationSeconds ?? Optional.Unspecified, + waveform = attachment.Waveform is null + ? Optional.Unspecified + : Convert.ToBase64String(attachment.Waveform) }); } diff --git a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs index c62426670c..f33eecfb9d 100644 --- a/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs +++ b/src/Discord.Net.Rest/API/Rest/UploadWebhookFileParams.cs @@ -1,8 +1,10 @@ using Discord.Net.Converters; using Discord.Net.Rest; using Newtonsoft.Json; +using System; using System.Collections.Generic; using System.IO; +using System.Linq; using System.Text; namespace Discord.API.Rest @@ -35,6 +37,9 @@ public IReadOnlyDictionary ToDictionary() { var d = new Dictionary(); + if (Files.Any(x => x.Waveform is not null && x.DurationSeconds is not null)) + Flags = Flags.GetValueOrDefault(MessageFlags.None) | MessageFlags.VoiceMessage; + var payload = new Dictionary(); if (Content.IsSpecified) payload["content"] = Content.Value; @@ -76,7 +81,11 @@ public IReadOnlyDictionary ToDictionary() { id = (ulong)n, filename = filename, - description = attachment.Description ?? Optional.Unspecified + description = attachment.Description ?? Optional.Unspecified, + duration_secs = attachment.DurationSeconds ?? Optional.Unspecified, + waveform = attachment.Waveform is null + ? Optional.Unspecified + : Convert.ToBase64String(attachment.Waveform) }); } diff --git a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs index 592b2a5f55..73906efe5e 100644 --- a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs +++ b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs @@ -1,5 +1,6 @@ using Discord.Rest; using System; +using System.Buffers.Text; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; @@ -35,6 +36,8 @@ public class Attachment : IAttachment /// public string Waveform { get; } /// + public byte[] WaveformBytes { get; } + /// public double? Duration { get; } /// @@ -69,6 +72,8 @@ internal Attachment(ulong id, string filename, string url, string proxyUrl, int Title = title; ClipParticipants = clipParticipants; ClipCreatedAt = clipCreatedAt; + if (waveform is not null) + WaveformBytes = Convert.FromBase64String(waveform); } internal static Attachment Create(Model model, BaseDiscordClient discord)