Skip to content

Commit

Permalink
Add voice status feature (#2532)
Browse files Browse the repository at this point in the history
  • Loading branch information
MinnDevelopment committed Dec 17, 2023
1 parent 8a360d5 commit 706e27c
Show file tree
Hide file tree
Showing 13 changed files with 251 additions and 1 deletion.
1 change: 1 addition & 0 deletions src/main/java/net/dv8tion/jda/api/Permission.java
Expand Up @@ -87,6 +87,7 @@ public enum Permission
VOICE_START_ACTIVITIES( 39, true, true, "Use Activities"),
VOICE_USE_SOUNDBOARD( 42, true, true, "Use Soundboard"),
VOICE_USE_EXTERNAL_SOUNDS(45, true, true, "Use External Sounds"),
VOICE_SET_STATUS( 48, true, true, "Set Voice Channel Status"),

// Stage Channel Permissions
REQUEST_TO_SPEAK( 32, true, true, "Request to Speak"),
Expand Down
22 changes: 22 additions & 0 deletions src/main/java/net/dv8tion/jda/api/audit/ActionType.java
Expand Up @@ -18,6 +18,7 @@

import net.dv8tion.jda.api.entities.Member;
import net.dv8tion.jda.api.entities.ScheduledEvent;
import net.dv8tion.jda.api.entities.channel.attribute.IVoiceStatusChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;

Expand Down Expand Up @@ -635,6 +636,27 @@ public enum ActionType
*/
AUTO_MODERATION_MEMBER_TIMEOUT( 145, TargetType.MEMBER),

/**
* A user updated the {@link IVoiceStatusChannel#getStatus() status} of a voice channel.
*
* <p><b>Possible Keys</b><br>
* <ul>
* <li>{@link AuditLogKey#CHANNEL_VOICE_STATUS CHANNEL_VOICE_STATUS}</li>
* <li>{@link AuditLogKey#CHANNEL_ID CHANNEL_ID}</li>
* </ul>
*/
VOICE_CHANNEL_STATUS_UPDATE(192, TargetType.CHANNEL),

/**
* A user removed the {@link IVoiceStatusChannel#getStatus() status} of a voice channel.
*
* <p><b>Possible Keys</b><br>
* <ul>
* <li>{@link AuditLogKey#CHANNEL_ID CHANNEL_ID}</li>
* </ul>
*/
VOICE_CHANNEL_STATUS_DELETE(193, TargetType.CHANNEL),

UNKNOWN(-1, TargetType.UNKNOWN);

private final int key;
Expand Down
8 changes: 8 additions & 0 deletions src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java
Expand Up @@ -240,6 +240,14 @@ public enum AuditLogKey
*/
CHANNEL_TOPIC("topic"),

/**
* Change of the {@link VoiceChannel#getStatus() VoiceChannel.getStatus()} value.
* <br>Only for {@link ChannelType#VOICE ChannelType.VOICE}
*
* <p>Expected type: <b>String</b>
*/
CHANNEL_VOICE_STATUS("status"),

/**
* Change of the {@link ISlowmodeChannel#getSlowmode()} value.
*
Expand Down
Expand Up @@ -168,6 +168,14 @@ public enum ChannelField
* @see VoiceChannel#getUserLimit()
*/
USER_LIMIT("userlimit", AuditLogKey.CHANNEL_USER_LIMIT),
/**
* The status of the channel.
*
* <p>Limited to {@link VoiceChannel Voice Channels}.
*
* @see VoiceChannel#getStatus()
*/
VOICE_STATUS("status", AuditLogKey.CHANNEL_VOICE_STATUS),


//Thread Specific
Expand Down
@@ -0,0 +1,68 @@
/*
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.dv8tion.jda.api.entities.channel.attribute;

import net.dv8tion.jda.api.Permission;
import net.dv8tion.jda.api.entities.channel.Channel;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;

import javax.annotation.CheckReturnValue;
import javax.annotation.Nonnull;

/**
* Channel with a modifiable voice status.
* <br>This can be used to indicate what is going on to people outside the channel.
*/
public interface IVoiceStatusChannel extends Channel
{
/** The maximum length of a voice status {@value} */
int MAX_STATUS_LENGTH = 500;

/**
* The current voice channel status.
* <br>This can be configured by users who are connected
* and have the {@link net.dv8tion.jda.api.Permission#VOICE_SET_STATUS set voice channel status} permission.
*
* @return The current voice channel status, or empty string if unset
*/
@Nonnull
String getStatus();

/**
* Change the current voice channel status.
* <br>This can be configured by users who are connected
* and have the {@link net.dv8tion.jda.api.Permission#VOICE_SET_STATUS set voice channel status} permission.
*
* @param status
* The new status, or empty to unset
*
* @throws IllegalArgumentException
* If the status is null or longer than {@value #MAX_STATUS_LENGTH} characters
* @throws net.dv8tion.jda.api.exceptions.MissingAccessException
* If the currently logged in account does not have {@link Permission#VIEW_CHANNEL Permission.VIEW_CHANNEL} in this channel
* @throws net.dv8tion.jda.api.exceptions.InsufficientPermissionException
* <ul>
* <li>If the currently logged in account is <b>not connected</b> and does not have the {@link Permission#MANAGE_CHANNEL MANAGE_CHANNEL} permission.</li>
* <li>If the currently logged in account is <b>connected</b> and does not have the {@link Permission#VOICE_SET_STATUS VOICE_SET_STATUS} permission.</li>
* </ul>
*
* @return {@link AuditableRestAction}
*/
@Nonnull
@CheckReturnValue
AuditableRestAction<Void> modifyStatus(@Nonnull String status);
}
Expand Up @@ -19,6 +19,7 @@
import net.dv8tion.jda.api.entities.Guild;
import net.dv8tion.jda.api.entities.channel.attribute.IAgeRestrictedChannel;
import net.dv8tion.jda.api.entities.channel.attribute.ISlowmodeChannel;
import net.dv8tion.jda.api.entities.channel.attribute.IVoiceStatusChannel;
import net.dv8tion.jda.api.entities.channel.attribute.IWebhookContainer;
import net.dv8tion.jda.api.entities.channel.middleman.AudioChannel;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
Expand Down Expand Up @@ -47,7 +48,7 @@
* @see JDA#getVoiceChannelsByName(String, boolean)
* @see JDA#getVoiceChannelById(long)
*/
public interface VoiceChannel extends StandardGuildChannel, GuildMessageChannel, AudioChannel, IWebhookContainer, IAgeRestrictedChannel, ISlowmodeChannel
public interface VoiceChannel extends StandardGuildChannel, GuildMessageChannel, AudioChannel, IWebhookContainer, IAgeRestrictedChannel, ISlowmodeChannel, IVoiceStatusChannel
{
/**
* The maximum limit you can set with {@link VoiceChannelManager#setUserLimit(int)}. ({@value})
Expand Down
@@ -0,0 +1,44 @@
/*
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.dv8tion.jda.api.events.channel.update;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.channel.Channel;
import net.dv8tion.jda.api.entities.channel.ChannelField;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;

import javax.annotation.Nonnull;

/**
* Indicates that a {@link Channel Channel's} voice channel status has been updated.
*
* <p>Can be used to retrieve the old status and the new one.
*
* <p>Limited to {@link VoiceChannel VoiceChannels}.
*
* @see VoiceChannel#getStatus()
*/
public class ChannelUpdateVoiceStatusEvent extends GenericChannelUpdateEvent<String>
{
public static final ChannelField FIELD = ChannelField.VOICE_STATUS;
public static final String IDENTIFIER = FIELD.getFieldName();

public ChannelUpdateVoiceStatusEvent(@Nonnull JDA api, long responseNumber, Channel channel, String oldValue, String newValue)
{
super(api, responseNumber, channel, FIELD, oldValue, newValue);
}
}
Expand Up @@ -212,6 +212,7 @@ public void onChannelUpdateDefaultReaction(@Nonnull ChannelUpdateDefaultReaction
public void onChannelUpdateDefaultSortOrder(@Nonnull ChannelUpdateDefaultSortOrderEvent event) {}
public void onChannelUpdateDefaultLayout(@Nonnull ChannelUpdateDefaultLayoutEvent event) {}
public void onChannelUpdateTopic(@Nonnull ChannelUpdateTopicEvent event) {}
public void onChannelUpdateVoiceStatus(@Nonnull ChannelUpdateVoiceStatusEvent event) {}
public void onChannelUpdateType(@Nonnull ChannelUpdateTypeEvent event) {}
public void onChannelUpdateUserLimit(@Nonnull ChannelUpdateUserLimitEvent event) {}
public void onChannelUpdateArchived(@Nonnull ChannelUpdateArchivedEvent event) {}
Expand Down
1 change: 1 addition & 0 deletions src/main/java/net/dv8tion/jda/api/requests/Route.java
Expand Up @@ -203,6 +203,7 @@ public static class Channels
public static final Route CREATE_PERM_OVERRIDE = new Route(PUT, "channels/{channel_id}/permissions/{permoverride_id}");
public static final Route MODIFY_PERM_OVERRIDE = new Route(PUT, "channels/{channel_id}/permissions/{permoverride_id}");
public static final Route DELETE_PERM_OVERRIDE = new Route(DELETE, "channels/{channel_id}/permissions/{permoverride_id}");
public static final Route SET_STATUS = new Route(PUT, "channels/{channel_id}/voice-status");

public static final Route SEND_TYPING = new Route(POST, "channels/{channel_id}/typing");
public static final Route GET_PERMISSIONS = new Route(GET, "channels/{channel_id}/permissions");
Expand Down
Expand Up @@ -1219,6 +1219,7 @@ public VoiceChannel createVoiceChannel(GuildImpl guild, DataObject json, long gu
.setParentCategory(json.getLong("parent_id", 0))
.setLatestMessageIdLong(json.getLong("last_message_id", 0))
.setName(json.getString("name"))
.setStatus(json.getString("status", ""))
.setPosition(json.getInt("position"))
.setUserLimit(json.getInt("user_limit"))
.setNSFW(json.getBoolean("nsfw"))
Expand Down
Expand Up @@ -26,8 +26,11 @@
import net.dv8tion.jda.api.entities.channel.concrete.Category;
import net.dv8tion.jda.api.entities.channel.concrete.VoiceChannel;
import net.dv8tion.jda.api.managers.channel.concrete.VoiceChannelManager;
import net.dv8tion.jda.api.requests.Route;
import net.dv8tion.jda.api.requests.restaction.AuditableRestAction;
import net.dv8tion.jda.api.requests.restaction.ChannelAction;
import net.dv8tion.jda.api.utils.MiscUtil;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.entities.GuildImpl;
import net.dv8tion.jda.internal.entities.channel.middleman.AbstractStandardGuildChannelImpl;
import net.dv8tion.jda.internal.entities.channel.mixin.attribute.IAgeRestrictedChannelMixin;
Expand All @@ -36,6 +39,7 @@
import net.dv8tion.jda.internal.entities.channel.mixin.middleman.AudioChannelMixin;
import net.dv8tion.jda.internal.entities.channel.mixin.middleman.GuildMessageChannelMixin;
import net.dv8tion.jda.internal.managers.channel.concrete.VoiceChannelManagerImpl;
import net.dv8tion.jda.internal.requests.restaction.AuditableRestActionImpl;
import net.dv8tion.jda.internal.utils.Checks;

import javax.annotation.Nonnull;
Expand All @@ -55,6 +59,7 @@ public class VoiceChannelImpl extends AbstractStandardGuildChannelImpl<VoiceChan
private final TLongObjectMap<Member> connectedMembers = MiscUtil.newLongMap();

private String region;
private String status = "";
private long latestMessageId;
private int bitrate;
private int userLimit;
Expand Down Expand Up @@ -162,6 +167,29 @@ public VoiceChannelManager getManager()
return new VoiceChannelManagerImpl(this);
}

@Nonnull
@Override
public String getStatus()
{
return status;
}

@Nonnull
@Override
public AuditableRestAction<Void> modifyStatus(@Nonnull String status)
{
Checks.notLonger(status, MAX_STATUS_LENGTH, "Voice Status");
checkCanAccessChannel();
if (this.equals(getGuild().getSelfMember().getVoiceState().getChannel()))
checkPermission(Permission.VOICE_SET_STATUS);
else
checkCanManage();

Route.CompiledRoute route = Route.Channels.SET_STATUS.compile(getId());
DataObject body = DataObject.empty().put("status", status.isEmpty() ? null : status);
return new AuditableRestActionImpl<>(api, route, body);
}

@Override
public TLongObjectMap<Member> getConnectedMembersMap()
{
Expand Down Expand Up @@ -210,6 +238,12 @@ public VoiceChannelImpl setLatestMessageIdLong(long latestMessageId)
return this;
}

public VoiceChannelImpl setStatus(String status)
{
this.status = status;
return this;
}

// -- Abstract Hooks --

@Override
Expand Down
@@ -0,0 +1,60 @@
/*
* Copyright 2015 Austin Keener, Michael Ritter, Florian Spieß, and the JDA contributors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package net.dv8tion.jda.internal.handle;

import net.dv8tion.jda.api.events.channel.update.ChannelUpdateVoiceStatusEvent;
import net.dv8tion.jda.api.utils.data.DataObject;
import net.dv8tion.jda.internal.JDAImpl;
import net.dv8tion.jda.internal.entities.channel.concrete.VoiceChannelImpl;

public class VoiceChannelStatusUpdateHandler extends SocketHandler
{
public VoiceChannelStatusUpdateHandler(JDAImpl api)
{
super(api);
}

@Override
protected Long handleInternally(DataObject content)
{
long guildId = content.getUnsignedLong("guild_id");
if (getJDA().getGuildSetupController().isLocked(guildId))
return guildId;

long id = content.getUnsignedLong("id");
VoiceChannelImpl channel = (VoiceChannelImpl) getJDA().getVoiceChannelsView().getElementById(id);

if (channel == null)
{
EventCache.LOG.debug("Caching VOICE_CHANNEL_STATUS_UPDATE for uncached channel. ID: {}", id);
getJDA().getEventCache().cache(EventCache.Type.CHANNEL, id, responseNumber, allContent, this::handle);
return null;
}

String newStatus = content.getString("status", "");
if (!newStatus.equals(channel.getStatus()))
{
String oldStatus = channel.getStatus();
channel.setStatus(newStatus);
api.handleEvent(
new ChannelUpdateVoiceStatusEvent(
api, responseNumber,
channel, oldStatus, newStatus));
}
return null;
}
}
Expand Up @@ -1416,6 +1416,7 @@ protected void setupHandlers()
handlers.put("USER_UPDATE", new UserUpdateHandler(api));
handlers.put("VOICE_SERVER_UPDATE", new VoiceServerUpdateHandler(api));
handlers.put("VOICE_STATE_UPDATE", new VoiceStateUpdateHandler(api));
handlers.put("VOICE_CHANNEL_STATUS_UPDATE", new VoiceChannelStatusUpdateHandler(api));

// Unused events
handlers.put("CHANNEL_PINS_ACK", nopHandler);
Expand Down

0 comments on commit 706e27c

Please sign in to comment.