diff --git a/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs b/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs
index 6f517d100..e3b51b614 100644
--- a/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs
+++ b/src/Discord.Net.Core/Entities/Channels/IStageChannel.cs
@@ -70,6 +70,51 @@ namespace Discord
///
Task StopStageAsync(RequestOptions options = null);
+ ///
+ /// Indicates that the bot would like to speak within a stage channel.
+ ///
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous request to speak operation.
+ ///
Task RequestToSpeak(RequestOptions options = null);
+
+ ///
+ /// Makes the current user become a speaker within a stage.
+ ///
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous speaker modify operation.
+ ///
+ Task BecomeSpeakerAsync(RequestOptions options = null);
+
+ ///
+ /// Makes the current user a listener.
+ ///
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous stop operation.
+ ///
+ Task StopSpeakingAsync(RequestOptions options = null);
+
+ ///
+ /// Makes a user a speaker within a stage.
+ ///
+ /// The user to make the speaker.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous move operation.
+ ///
+ Task MoveToSpeaker(IGuildUser user, RequestOptions options = null);
+
+ ///
+ /// Removes a user from speaking.
+ ///
+ /// The user to remove from speaking.
+ /// The options to be used when sending the request.
+ ///
+ /// A task that represents the asynchronous remove operation.
+ ///
+ Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null);
}
}
diff --git a/src/Discord.Net.Rest/DiscordRestApiClient.cs b/src/Discord.Net.Rest/DiscordRestApiClient.cs
index e8565b678..3e9ed4393 100644
--- a/src/Discord.Net.Rest/DiscordRestApiClient.cs
+++ b/src/Discord.Net.Rest/DiscordRestApiClient.cs
@@ -646,6 +646,18 @@ namespace Discord.API
await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/@me", args, bucket, options: options).ConfigureAwait(false);
}
+ public async Task ModifyUserVoiceState(ulong guildId, ulong userId, ModifyVoiceStateParams args, RequestOptions options = null)
+ {
+ Preconditions.NotEqual(guildId, 0, nameof(guildId));
+ Preconditions.NotEqual(userId, 0, nameof(userId));
+
+ options = RequestOptions.CreateOrClone(options);
+
+ var bucket = new BucketIds();
+
+ await SendJsonAsync("PATCH", () => $"guilds/{guildId}/voice-states/{userId}", args, bucket, options: options).ConfigureAwait(false);
+ }
+
// roles
public async Task AddRoleAsync(ulong guildId, ulong userId, ulong roleId, RequestOptions options = null)
{
diff --git a/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs b/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs
index 883a080f1..c5bad43da 100644
--- a/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs
+++ b/src/Discord.Net.Rest/Entities/Channels/RestStageChannel.cs
@@ -105,5 +105,51 @@ namespace Discord.Rest
};
return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
}
+
+ ///
+ public Task BecomeSpeakerAsync(RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = false
+ };
+ return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
+ }
+
+ ///
+ public Task StopSpeakingAsync(RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = true
+ };
+ return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
+ }
+
+ ///
+ public Task MoveToSpeaker(IGuildUser user, RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = false
+ };
+
+ return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args);
+ }
+
+ ///
+ public Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = true
+ };
+
+ return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args);
+ }
}
}
diff --git a/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs b/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs
index 15e49901e..fb87a0591 100644
--- a/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs
+++ b/src/Discord.Net.WebSocket/Entities/Channels/SocketStageChannel.cs
@@ -27,6 +27,12 @@ namespace Discord.WebSocket
///
public bool Live { get; private set; } = false;
+ ///
+ /// Returns if the current user is a speaker within the stage, otherwise .
+ ///
+ public bool IsSpeaker
+ => !Guild.CurrentUser.IsSuppressed;
+
///
/// Gets a collection of users who are speakers within the stage.
///
@@ -112,5 +118,51 @@ namespace Discord.WebSocket
};
return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
}
+
+ ///
+ public Task BecomeSpeakerAsync(RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = false
+ };
+ return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
+ }
+
+ ///
+ public Task StopSpeakingAsync(RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = true
+ };
+ return Discord.ApiClient.ModifyMyVoiceState(this.Guild.Id, args, options);
+ }
+
+ ///
+ public Task MoveToSpeaker(IGuildUser user, RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = false
+ };
+
+ return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args);
+ }
+
+ ///
+ public Task RemoveFromSpeaker(IGuildUser user, RequestOptions options = null)
+ {
+ var args = new API.Rest.ModifyVoiceStateParams()
+ {
+ ChannelId = this.Id,
+ Suppressed = true
+ };
+
+ return Discord.ApiClient.ModifyUserVoiceState(this.Guild.Id, user.Id, args);
+ }
}
}