summaryrefslogtreecommitdiff
path: root/src/discord/discord.cpp
diff options
context:
space:
mode:
authorouwou <26526779+ouwou@users.noreply.github.com>2024-07-05 03:51:58 -0400
committerGitHub <noreply@github.com>2024-07-05 03:51:58 -0400
commit68db143c8939e12dd569d6ac737213ad856c139b (patch)
treed5e814329fb19912b69b9804fc68b852674d8277 /src/discord/discord.cpp
parente6191d95341d164eacaf91739c8aa7020dd5c9b6 (diff)
parentb19782c16dffd38ac5651641131a48f8ff961b32 (diff)
downloadabaddon-portaudio-68db143c8939e12dd569d6ac737213ad856c139b.tar.gz
abaddon-portaudio-68db143c8939e12dd569d6ac737213ad856c139b.zip
Merge pull request #279 from uowuo/stages
Support for stages
Diffstat (limited to 'src/discord/discord.cpp')
-rw-r--r--src/discord/discord.cpp159
1 files changed, 154 insertions, 5 deletions
diff --git a/src/discord/discord.cpp b/src/discord/discord.cpp
index 062a871..a7712d6 100644
--- a/src/discord/discord.cpp
+++ b/src/discord/discord.cpp
@@ -360,6 +360,14 @@ std::optional<WebhookMessageData> DiscordClient::GetWebhookMessageData(Snowflake
return m_store.GetWebhookMessage(message_id);
}
+std::optional<StageInstance> DiscordClient::GetStageInstanceFromChannel(Snowflake channel_id) const {
+ const auto iter1 = m_channel_to_stage_instance.find(channel_id);
+ if (iter1 == m_channel_to_stage_instance.end()) return {};
+ const auto iter2 = m_stage_instances.find(iter1->second);
+ if (iter2 == m_stage_instances.end()) return {};
+ return iter2->second;
+}
+
bool DiscordClient::IsThreadJoined(Snowflake thread_id) const {
return std::find(m_joined_threads.begin(), m_joined_threads.end(), thread_id) != m_joined_threads.end();
}
@@ -462,6 +470,10 @@ bool DiscordClient::CanManageMember(Snowflake guild_id, Snowflake actor, Snowfla
return actor_highest->Position > target_highest->Position;
}
+bool DiscordClient::IsStageModerator(Snowflake user_id, Snowflake channel_id) const {
+ return HasChannelPermission(user_id, channel_id, Permission::MANAGE_CHANNELS | Permission::MOVE_MEMBERS | Permission::MUTE_MEMBERS);
+}
+
void DiscordClient::ChatMessageCallback(const std::string &nonce, const http::response_type &response, const sigc::slot<void(DiscordError)> &callback) {
if (!CheckCode(response)) {
if (response.status_code == http::TooManyRequests) {
@@ -1288,6 +1300,78 @@ std::optional<uint32_t> DiscordClient::GetSSRCOfUser(Snowflake id) const {
return m_voice.GetSSRCOfUser(id);
}
+bool DiscordClient::IsUserSpeaker(Snowflake user_id) const {
+ const auto state = GetVoiceState(user_id);
+ return state.has_value() && state->second.IsSpeaker();
+}
+
+bool DiscordClient::HasUserRequestedToSpeak(Snowflake user_id) const {
+ const auto state = GetVoiceState(user_id);
+ return state.has_value() && state->second.RequestToSpeakTimestamp.has_value() && util::FlagSet(state->second.Flags, VoiceStateFlags::Suppressed);
+}
+
+bool DiscordClient::IsUserInvitedToSpeak(Snowflake user_id) const {
+ const auto state = GetVoiceState(user_id);
+ return state.has_value() && state->second.RequestToSpeakTimestamp.has_value() && !util::FlagSet(state->second.Flags, VoiceStateFlags::Suppressed);
+}
+
+void DiscordClient::RequestToSpeak(Snowflake channel_id, bool want, const sigc::slot<void(DiscordError code)> &callback) {
+ if (want && !HasSelfChannelPermission(channel_id, Permission::REQUEST_TO_SPEAK)) return;
+ const auto channel = GetChannel(channel_id);
+ if (!channel.has_value() || !channel->GuildID.has_value()) return;
+
+ ModifyCurrentUserVoiceStateObject d;
+ d.ChannelID = channel_id;
+ if (want) {
+ d.RequestToSpeakTimestamp = Glib::DateTime::create_now_utc().format_iso8601();
+ } else {
+ d.RequestToSpeakTimestamp = "";
+ }
+ m_http.MakePATCH("/guilds/" + std::to_string(*channel->GuildID) + "/voice-states/@me", nlohmann::json(d).dump(), [callback](const http::response_type &response) {
+ if (CheckCode(response, 204)) {
+ callback(DiscordError::NONE);
+ } else {
+ callback(GetCodeFromResponse(response));
+ }
+ });
+}
+
+void DiscordClient::SetStageSpeaking(Snowflake channel_id, bool want, const sigc::slot<void(DiscordError code)> &callback) {
+ const auto channel = GetChannel(channel_id);
+ if (!channel.has_value() || !channel->GuildID.has_value()) return;
+
+ ModifyCurrentUserVoiceStateObject d;
+ d.ChannelID = channel_id;
+ d.Suppress = !want;
+ if (want) {
+ d.RequestToSpeakTimestamp = "";
+ }
+ m_http.MakePATCH("/guilds/" + std::to_string(*channel->GuildID) + "/voice-states/@me", nlohmann::json(d).dump(), [callback](const http::response_type &response) {
+ if (CheckCode(response, 204)) {
+ callback(DiscordError::NONE);
+ } else {
+ callback(GetCodeFromResponse(response));
+ }
+ });
+}
+
+void DiscordClient::DeclineInviteToSpeak(Snowflake channel_id, const sigc::slot<void(DiscordError code)> &callback) {
+ const auto channel = GetChannel(channel_id);
+ if (!channel.has_value() || !channel->GuildID.has_value()) return;
+
+ ModifyCurrentUserVoiceStateObject d;
+ d.ChannelID = channel_id;
+ d.Suppress = true;
+ d.RequestToSpeakTimestamp = "";
+ m_http.MakePATCH("/guilds/" + std::to_string(*channel->GuildID) + "/voice-states/@me", nlohmann::json(d).dump(), [callback](const http::response_type &response) {
+ if (CheckCode(response, 204)) {
+ callback(DiscordError::NONE);
+ } else {
+ callback(GetCodeFromResponse(response));
+ }
+ });
+}
+
DiscordVoiceClient &DiscordClient::GetVoiceClient() {
return m_voice;
}
@@ -1303,7 +1387,7 @@ void DiscordClient::SetVoiceDeafened(bool is_deaf) {
}
#endif
-std::optional<std::pair<Snowflake, VoiceStateFlags>> DiscordClient::GetVoiceState(Snowflake user_id) const {
+std::optional<std::pair<Snowflake, PackedVoiceState>> DiscordClient::GetVoiceState(Snowflake user_id) const {
if (const auto it = m_voice_states.find(user_id); it != m_voice_states.end()) {
return it->second;
}
@@ -1652,6 +1736,15 @@ void DiscordClient::HandleGatewayMessage(std::string str) {
case GatewayEvent::GUILD_MEMBERS_CHUNK: {
HandleGatewayGuildMembersChunk(m);
} break;
+ case GatewayEvent::STAGE_INSTANCE_CREATE: {
+ HandleGatewayStageInstanceCreate(m);
+ } break;
+ case GatewayEvent::STAGE_INSTANCE_UPDATE: {
+ HandleGatewayStageInstanceUpdate(m);
+ } break;
+ case GatewayEvent::STAGE_INSTANCE_DELETE: {
+ HandleGatewayStageInstanceDelete(m);
+ } break;
case GatewayEvent::VOICE_STATE_UPDATE: {
HandleGatewayVoiceStateUpdate(m);
} break;
@@ -1712,6 +1805,14 @@ void DiscordClient::ProcessNewGuild(GuildData &guild) {
return;
}
+ if (guild.StageInstances.has_value()) {
+ for (const auto &stage : *guild.StageInstances) {
+ spdlog::get("discord")->debug("storing stage {} in channel {}", stage.ID, stage.ChannelID);
+ m_stage_instances[stage.ID] = stage;
+ m_channel_to_stage_instance[stage.ChannelID] = stage.ID;
+ }
+ }
+
m_store.BeginTransaction();
m_store.SetGuild(guild.ID, guild);
@@ -2302,6 +2403,29 @@ void DiscordClient::HandleGatewayGuildMembersChunk(const GatewayMessage &msg) {
m_store.EndTransaction();
}
+void DiscordClient::HandleGatewayStageInstanceCreate(const GatewayMessage &msg) {
+ StageInstance data = msg.Data;
+ spdlog::get("discord")->debug("STAGE_INSTANCE_CREATE: {} in {}", data.ID, data.ChannelID);
+ m_stage_instances[data.ID] = data;
+ m_channel_to_stage_instance[data.ChannelID] = data.ID;
+ m_signal_stage_instance_create.emit(data);
+}
+
+void DiscordClient::HandleGatewayStageInstanceUpdate(const GatewayMessage &msg) {
+ StageInstance data = msg.Data;
+ spdlog::get("discord")->debug("STAGE_INSTANCE_UPDATE: {} in {}", data.ID, data.ChannelID);
+ m_stage_instances[data.ID] = data;
+ m_signal_stage_instance_update.emit(data);
+}
+
+void DiscordClient::HandleGatewayStageInstanceDelete(const GatewayMessage &msg) {
+ StageInstance data = msg.Data;
+ spdlog::get("discord")->debug("STAGE_INSTANCE_DELETE: {} in {}", data.ID, data.ChannelID);
+ m_stage_instances.erase(data.ID);
+ m_channel_to_stage_instance.erase(data.ChannelID);
+ m_signal_stage_instance_delete.emit(data);
+}
+
#ifdef WITH_VOICE
/*
@@ -2399,9 +2523,14 @@ void DiscordClient::CheckVoiceState(const VoiceState &data) {
if (data.ChannelID.has_value()) {
const auto old_state = GetVoiceState(data.UserID);
SetVoiceState(data.UserID, data);
- if (old_state.has_value() && old_state->first != *data.ChannelID) {
- m_signal_voice_user_disconnect.emit(data.UserID, old_state->first);
- m_signal_voice_user_connect.emit(data.UserID, *data.ChannelID);
+ const auto new_state = GetVoiceState(data.UserID);
+ if (old_state.has_value()) {
+ if (old_state->first != *data.ChannelID) {
+ m_signal_voice_user_disconnect.emit(data.UserID, old_state->first);
+ m_signal_voice_user_connect.emit(data.UserID, *data.ChannelID);
+ } else if (old_state->second.IsSpeaker() != new_state.value().second.IsSpeaker()) {
+ m_signal_voice_speaker_state_changed.emit(*data.ChannelID, data.UserID, new_state->second.IsSpeaker());
+ }
} else if (!old_state.has_value()) {
m_signal_voice_user_connect.emit(data.UserID, *data.ChannelID);
}
@@ -2954,8 +3083,9 @@ void DiscordClient::SetVoiceState(Snowflake user_id, const VoiceState &state) {
if (state.IsDeafened) flags |= VoiceStateFlags::Deaf;
if (state.IsSelfStream) flags |= VoiceStateFlags::SelfStream;
if (state.IsSelfVideo) flags |= VoiceStateFlags::SelfVideo;
+ if (state.IsSuppressed) flags |= VoiceStateFlags::Suppressed;
- m_voice_states[user_id] = std::make_pair(*state.ChannelID, flags);
+ m_voice_states[user_id] = std::make_pair(*state.ChannelID, PackedVoiceState { flags, state.RequestToSpeakTimestamp });
m_voice_state_channel_users[*state.ChannelID].insert(user_id);
m_signal_voice_state_set.emit(user_id, *state.ChannelID, flags);
@@ -3018,6 +3148,9 @@ void DiscordClient::LoadEventMap() {
m_event_map["VOICE_STATE_UPDATE"] = GatewayEvent::VOICE_STATE_UPDATE;
m_event_map["VOICE_SERVER_UPDATE"] = GatewayEvent::VOICE_SERVER_UPDATE;
m_event_map["CALL_CREATE"] = GatewayEvent::CALL_CREATE;
+ m_event_map["STAGE_INSTANCE_CREATE"] = GatewayEvent::STAGE_INSTANCE_CREATE;
+ m_event_map["STAGE_INSTANCE_UPDATE"] = GatewayEvent::STAGE_INSTANCE_UPDATE;
+ m_event_map["STAGE_INSTANCE_DELETE"] = GatewayEvent::STAGE_INSTANCE_DELETE;
}
DiscordClient::type_signal_gateway_ready DiscordClient::signal_gateway_ready() {
@@ -3196,6 +3329,18 @@ DiscordClient::type_signal_guild_members_chunk DiscordClient::signal_guild_membe
return m_signal_guild_members_chunk;
}
+DiscordClient::type_signal_stage_instance_create DiscordClient::signal_stage_instance_create() {
+ return m_signal_stage_instance_create;
+}
+
+DiscordClient::type_signal_stage_instance_update DiscordClient::signal_stage_instance_update() {
+ return m_signal_stage_instance_update;
+}
+
+DiscordClient::type_signal_stage_instance_delete DiscordClient::signal_stage_instance_delete() {
+ return m_signal_stage_instance_delete;
+}
+
DiscordClient::type_signal_added_to_thread DiscordClient::signal_added_to_thread() {
return m_signal_added_to_thread;
}
@@ -3273,3 +3418,7 @@ DiscordClient::type_signal_voice_user_connect DiscordClient::signal_voice_user_c
DiscordClient::type_signal_voice_state_set DiscordClient::signal_voice_state_set() {
return m_signal_voice_state_set;
}
+
+DiscordClient::type_signal_voice_speaker_state_changed DiscordClient::signal_voice_speaker_state_changed() {
+ return m_signal_voice_speaker_state_changed;
+} \ No newline at end of file