diff --git a/src/Discord.Net.Core/DiscordErrorCode.cs b/src/Discord.Net.Core/DiscordErrorCode.cs
index 2dc389cb..29f1b9d1 100644
--- a/src/Discord.Net.Core/DiscordErrorCode.cs
+++ b/src/Discord.Net.Core/DiscordErrorCode.cs
@@ -188,6 +188,7 @@ namespace Discord
CannotConvertBetweenPremiumEmojiAndNormalEmoji = 50145,
UploadedFileNotFound = 50146,
FeatureInProcessOfRollingOut = 50155,
+ CannotSendVoiceMessageInThisChannel = 50173,
MissingPermissionToSendThisSticker = 50600,
#endregion
diff --git a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs
index 277c0629..55d2596e 100644
--- a/src/Discord.Net.Core/Entities/Messages/IAttachment.cs
+++ b/src/Discord.Net.Core/Entities/Messages/IAttachment.cs
@@ -70,5 +70,15 @@ namespace Discord
/// Gets the media's MIME type if present; otherwise .
///
string ContentType { get; }
+
+ ///
+ /// Gets the duration of the audio file. if the attachment is not a voice message.
+ ///
+ double? Duration { get; }
+
+ ///
+ /// Gets the base64 encoded bytearray representing a sampled waveform. if the attachment is not a voice message.
+ ///
+ public string Waveform { get; }
}
}
diff --git a/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs b/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs
index 4854dc99..10f1aeba 100644
--- a/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs
+++ b/src/Discord.Net.Core/Entities/Messages/MessageFlags.cs
@@ -51,6 +51,11 @@ namespace Discord
///
/// Flag give to messages that will not trigger push and desktop notifications.
///
- SuppressNotification = 1 << 12
+ SuppressNotification = 1 << 12,
+
+ ///
+ /// This message is a voice message.
+ ///
+ VoiceMessage = 1 << 13,
}
}
diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
index 21026b99..becbba1a 100644
--- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermission.cs
@@ -177,5 +177,10 @@ namespace Discord
/// Allows members to edit and cancel events in this channel.
///
CreateEvents = 1L << 44,
+
+ ///
+ /// Allows sending voice messages.
+ ///
+ SendVoiceMessages = 1L << 46,
}
}
diff --git a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
index 8ef01f26..ca1ddc29 100644
--- a/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/ChannelPermissions.cs
@@ -18,22 +18,22 @@ namespace Discord
///
/// Gets a that grants all permissions for text channels.
///
- public static readonly ChannelPermissions Text = new(0b01_001111_110010_110011_111101_111111_111101_010001);
+ public static readonly ChannelPermissions Text = new(0b10001_001111_110010_110011_111101_111111_111101_010001);
///
/// Gets a that grants all permissions for voice channels.
///
- public static readonly ChannelPermissions Voice = new(0b01_001010_001010_110011_111101_111111_111101_010001); // (0b1_00000_0000100_1111110_0000000011100_010001 (<- voice only perms) |= Text)
-
+ public static readonly ChannelPermissions Voice = new(0b10001_001010_001010_110011_111101_111111_111101_010001);
+
///
/// Gets a that grants all permissions for stage channels.
///
- public static readonly ChannelPermissions Stage = new(0b0010_001110_010001_010101_111111_111001_010001);
+ public static readonly ChannelPermissions Stage = new(0b10000_000010_001110_010001_010101_111111_111001_010001);
///
/// Gets a that grants all permissions for category channels.
///
- public static readonly ChannelPermissions Category = new(0b01100_1111110_1111111110001_010001);
+ public static readonly ChannelPermissions Category = new(0b011001_001111_111110_110011_111101_111111_111101_010001);
///
/// Gets a that grants all permissions for direct message channels.
@@ -140,6 +140,8 @@ namespace Discord
public bool UseSoundboard => Permissions.GetValue(RawValue, ChannelPermission.UseSoundboard);
/// If , a user can edit and cancel events in this channel.
public bool CreateEvents => Permissions.GetValue(RawValue, ChannelPermission.CreateEvents);
+ /// If , a user can send voice messages in this channel.
+ public bool SendVoiceMessages => Permissions.GetValue(RawValue, ChannelPermission.SendVoiceMessages);
/// Creates a new with the provided packed value.
public ChannelPermissions(ulong rawValue) { RawValue = rawValue; }
@@ -176,7 +178,8 @@ namespace Discord
bool? sendMessagesInThreads = null,
bool? startEmbeddedActivities = null,
bool? useSoundboard = null,
- bool? createEvents = null)
+ bool? createEvents = null,
+ bool? sendVoiceMessages = null)
{
ulong value = initialValue;
@@ -212,6 +215,7 @@ namespace Discord
Permissions.SetValue(ref value, startEmbeddedActivities, ChannelPermission.StartEmbeddedActivities);
Permissions.SetValue(ref value, useSoundboard, ChannelPermission.UseSoundboard);
Permissions.SetValue(ref value, createEvents, ChannelPermission.CreateEvents);
+ Permissions.SetValue(ref value, sendVoiceMessages, ChannelPermission.SendVoiceMessages);
RawValue = value;
}
@@ -249,12 +253,13 @@ namespace Discord
bool sendMessagesInThreads = false,
bool startEmbeddedActivities = false,
bool useSoundboard = false,
- bool createEvents = false)
+ bool createEvents = false,
+ bool sendVoiceMessages = false)
: this(0, createInstantInvite, manageChannel, addReactions, viewChannel, sendMessages, sendTTSMessages, manageMessages,
embedLinks, attachFiles, readMessageHistory, mentionEveryone, useExternalEmojis, connect,
speak, muteMembers, deafenMembers, moveMembers, useVoiceActivation, prioritySpeaker, stream, manageRoles, manageWebhooks,
useApplicationCommands, requestToSpeak, manageThreads, createPublicThreads, createPrivateThreads, useExternalStickers, sendMessagesInThreads,
- startEmbeddedActivities, useSoundboard, createEvents)
+ startEmbeddedActivities, useSoundboard, createEvents, sendVoiceMessages)
{ }
/// Creates a new from this one, changing the provided non-null permissions.
@@ -290,7 +295,8 @@ namespace Discord
bool? sendMessagesInThreads = null,
bool? startEmbeddedActivities = null,
bool? useSoundboard = null,
- bool? createEvents = null)
+ bool? createEvents = null,
+ bool? sendVoiceMessages = null)
=> new ChannelPermissions(RawValue,
createInstantInvite,
manageChannel,
@@ -323,7 +329,8 @@ namespace Discord
sendMessagesInThreads,
startEmbeddedActivities,
useSoundboard,
- createEvents);
+ createEvents,
+ sendVoiceMessages);
public bool Has(ChannelPermission permission) => Permissions.GetValue(RawValue, permission);
diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
index 41f3be24..1485e0ba 100644
--- a/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermission.cs
@@ -262,5 +262,10 @@ namespace Discord
/// Allows for using the soundboard.
///
UseSoundboard = 1L << 42,
+
+ ///
+ /// Allows sending voice messages.
+ ///
+ SendVoiceMessages = 1L << 46,
}
}
diff --git a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
index 4884a14e..071fc6f4 100644
--- a/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
+++ b/src/Discord.Net.Core/Entities/Permissions/GuildPermissions.cs
@@ -108,6 +108,8 @@ namespace Discord
public bool UseSoundboard => Permissions.GetValue(RawValue, GuildPermission.UseSoundboard);
/// If , a user can view monetization analytics in this guild.
public bool ViewMonetizationAnalytics => Permissions.GetValue(RawValue, GuildPermission.ViewMonetizationAnalytics);
+ /// If , a user can send voice messages in this channel.
+ public bool SendVoiceMessages => Permissions.GetValue(RawValue, GuildPermission.SendVoiceMessages);
/// Creates a new with the provided packed value.
public GuildPermissions(ulong rawValue) { RawValue = rawValue; }
@@ -158,7 +160,8 @@ namespace Discord
bool? startEmbeddedActivities = null,
bool? moderateMembers = null,
bool? useSoundboard = null,
- bool? viewMonetizationAnalytics = null)
+ bool? viewMonetizationAnalytics = null,
+ bool? sendVoiceMessages = null)
{
ulong value = initialValue;
@@ -205,6 +208,7 @@ namespace Discord
Permissions.SetValue(ref value, moderateMembers, GuildPermission.ModerateMembers);
Permissions.SetValue(ref value, useSoundboard, GuildPermission.UseSoundboard);
Permissions.SetValue(ref value, viewMonetizationAnalytics, GuildPermission.ViewMonetizationAnalytics);
+ Permissions.SetValue(ref value, sendVoiceMessages, GuildPermission.SendVoiceMessages);
RawValue = value;
}
@@ -253,7 +257,8 @@ namespace Discord
bool startEmbeddedActivities = false,
bool moderateMembers = false,
bool useSoundboard = false,
- bool viewMonetizationAnalytics = false)
+ bool viewMonetizationAnalytics = false,
+ bool sendVoiceMessages = false)
: this(0,
createInstantInvite: createInstantInvite,
manageRoles: manageRoles,
@@ -297,7 +302,8 @@ namespace Discord
startEmbeddedActivities: startEmbeddedActivities,
moderateMembers: moderateMembers,
useSoundboard: useSoundboard,
- viewMonetizationAnalytics: viewMonetizationAnalytics)
+ viewMonetizationAnalytics: viewMonetizationAnalytics,
+ sendVoiceMessages: sendVoiceMessages)
{ }
/// Creates a new from this one, changing the provided non-null permissions.
@@ -344,13 +350,14 @@ namespace Discord
bool? startEmbeddedActivities = null,
bool? moderateMembers = null,
bool? useSoundboard = null,
- bool? viewMonetizationAnalytics = null)
+ bool? viewMonetizationAnalytics = null,
+ bool? sendVoiceMessages = null)
=> new GuildPermissions(RawValue, createInstantInvite, kickMembers, banMembers, administrator, manageChannels, manageGuild, addReactions,
viewAuditLog, viewGuildInsights, viewChannel, sendMessages, sendTTSMessages, manageMessages, embedLinks, attachFiles,
readMessageHistory, mentionEveryone, useExternalEmojis, connect, speak, muteMembers, deafenMembers, moveMembers,
useVoiceActivation, prioritySpeaker, stream, changeNickname, manageNicknames, manageRoles, manageWebhooks, manageEmojisAndStickers,
useApplicationCommands, requestToSpeak, manageEvents, manageThreads, createPublicThreads, createPrivateThreads, useExternalStickers, sendMessagesInThreads,
- startEmbeddedActivities, moderateMembers, useSoundboard, viewMonetizationAnalytics);
+ startEmbeddedActivities, moderateMembers, useSoundboard, viewMonetizationAnalytics, sendVoiceMessages);
///
/// Returns a value that indicates if a specific is enabled
diff --git a/src/Discord.Net.Rest/API/Common/Attachment.cs b/src/Discord.Net.Rest/API/Common/Attachment.cs
index 7970dc9a..e26cddb5 100644
--- a/src/Discord.Net.Rest/API/Common/Attachment.cs
+++ b/src/Discord.Net.Rest/API/Common/Attachment.cs
@@ -24,5 +24,9 @@ namespace Discord.API
public Optional Width { get; set; }
[JsonProperty("ephemeral")]
public Optional Ephemeral { get; set; }
+ [JsonProperty("duration_secs")]
+ public Optional DurationSeconds { get; set; }
+ [JsonProperty("waveform")]
+ public Optional Waveform { get; set; }
}
}
diff --git a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs
index a5b83fb7..fef5207d 100644
--- a/src/Discord.Net.Rest/Entities/Messages/Attachment.cs
+++ b/src/Discord.Net.Rest/Entities/Messages/Attachment.cs
@@ -27,9 +27,13 @@ namespace Discord
public string Description { get; }
///
public string ContentType { get; }
+ ///
+ public string Waveform { get; }
+ ///
+ public double? Duration { get; }
internal Attachment(ulong id, string filename, string url, string proxyUrl, int size, int? height, int? width,
- bool? ephemeral, string description, string contentType)
+ bool? ephemeral, string description, string contentType, double? duration, string waveform)
{
Id = id;
Filename = filename;
@@ -41,6 +45,8 @@ namespace Discord
Ephemeral = ephemeral.GetValueOrDefault(false);
Description = description;
ContentType = contentType;
+ Duration = duration;
+ Waveform = waveform;
}
internal static Attachment Create(Model model)
{
@@ -48,7 +54,9 @@ namespace Discord
model.Height.IsSpecified ? model.Height.Value : (int?)null,
model.Width.IsSpecified ? model.Width.Value : (int?)null,
model.Ephemeral.ToNullable(), model.Description.GetValueOrDefault(),
- model.ContentType.GetValueOrDefault());
+ model.ContentType.GetValueOrDefault(),
+ model.DurationSeconds.IsSpecified ? model.DurationSeconds.Value : null,
+ model.Waveform.GetValueOrDefault(null));
}
///
diff --git a/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs b/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs
index f8300cc6..bf88341a 100644
--- a/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs
+++ b/test/Discord.Net.Tests.Unit/ChannelPermissionsTests.cs
@@ -92,6 +92,7 @@ namespace Discord
AssertFlag(() => new ChannelPermissions(startEmbeddedActivities: true), ChannelPermission.StartEmbeddedActivities);
AssertFlag(() => new ChannelPermissions(useSoundboard: true), ChannelPermission.UseSoundboard);
AssertFlag(() => new ChannelPermissions(createEvents: true), ChannelPermission.CreateEvents);
+ AssertFlag(() => new ChannelPermissions(sendVoiceMessages: true), ChannelPermission.SendVoiceMessages);
}
///
@@ -156,6 +157,7 @@ namespace Discord
AssertUtil(ChannelPermission.ManageWebhooks, x => x.ManageWebhooks, (p, enable) => p.Modify(manageWebhooks: enable));
AssertUtil(ChannelPermission.PrioritySpeaker, x => x.PrioritySpeaker, (p, enable) => p.Modify(prioritySpeaker: enable));
AssertUtil(ChannelPermission.Stream, x => x.Stream, (p, enable) => p.Modify(stream: enable));
+ AssertUtil(ChannelPermission.SendVoiceMessages, x => x.SendVoiceMessages, (p, enable) => p.Modify(sendVoiceMessages: enable));
}
///
diff --git a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs
index e259cc01..73f4a692 100644
--- a/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs
+++ b/test/Discord.Net.Tests.Unit/GuildPermissionsTests.cs
@@ -102,6 +102,7 @@ namespace Discord
AssertFlag(() => new GuildPermissions(moderateMembers: true), GuildPermission.ModerateMembers);
AssertFlag(() => new GuildPermissions(viewMonetizationAnalytics: true), GuildPermission.ViewMonetizationAnalytics);
AssertFlag(() => new GuildPermissions(useSoundboard: true), GuildPermission.UseSoundboard);
+ AssertFlag(() => new GuildPermissions(sendVoiceMessages: true), GuildPermission.SendVoiceMessages);
}
///
@@ -180,6 +181,9 @@ namespace Discord
AssertUtil(GuildPermission.CreatePrivateThreads, x => x.CreatePrivateThreads, (p, enable) => p.Modify(createPrivateThreads: enable));
AssertUtil(GuildPermission.UseExternalStickers, x => x.UseExternalStickers, (p, enable) => p.Modify(useExternalStickers: enable));
AssertUtil(GuildPermission.ModerateMembers, x => x.ModerateMembers, (p, enable) => p.Modify(moderateMembers: enable));
+ AssertUtil(GuildPermission.ViewMonetizationAnalytics, x => x.ViewMonetizationAnalytics, (p, enable) => p.Modify(viewMonetizationAnalytics: enable));
+ AssertUtil(GuildPermission.UseSoundboard, x => x.UseSoundboard, (p, enable) => p.Modify(useSoundboard: enable));
+ AssertUtil(GuildPermission.SendVoiceMessages, x => x.SendVoiceMessages, (p, enable) => p.Modify(sendVoiceMessages: enable));
}
}
}