diff --git a/src/main/java/net/dv8tion/jda/api/Permission.java b/src/main/java/net/dv8tion/jda/api/Permission.java
index 313a4fbd3d..22e99f903d 100644
--- a/src/main/java/net/dv8tion/jda/api/Permission.java
+++ b/src/main/java/net/dv8tion/jda/api/Permission.java
@@ -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"),
diff --git a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java
index 32efb8933e..ba216cc69c 100644
--- a/src/main/java/net/dv8tion/jda/api/audit/ActionType.java
+++ b/src/main/java/net/dv8tion/jda/api/audit/ActionType.java
@@ -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;
@@ -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.
+ *
+ *
Possible Keys
+ *
+ * - {@link AuditLogKey#CHANNEL_VOICE_STATUS CHANNEL_VOICE_STATUS}
+ * - {@link AuditLogKey#CHANNEL_ID CHANNEL_ID}
+ *
+ */
+ VOICE_CHANNEL_STATUS_UPDATE(192, TargetType.CHANNEL),
+
+ /**
+ * A user removed the {@link IVoiceStatusChannel#getStatus() status} of a voice channel.
+ *
+ * Possible Keys
+ *
+ * - {@link AuditLogKey#CHANNEL_ID CHANNEL_ID}
+ *
+ */
+ VOICE_CHANNEL_STATUS_DELETE(193, TargetType.CHANNEL),
+
UNKNOWN(-1, TargetType.UNKNOWN);
private final int key;
diff --git a/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java b/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java
index e4e6831ed6..7b1522aac9 100644
--- a/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java
+++ b/src/main/java/net/dv8tion/jda/api/audit/AuditLogKey.java
@@ -240,6 +240,14 @@ public enum AuditLogKey
*/
CHANNEL_TOPIC("topic"),
+ /**
+ * Change of the {@link VoiceChannel#getStatus() VoiceChannel.getStatus()} value.
+ *
Only for {@link ChannelType#VOICE ChannelType.VOICE}
+ *
+ * Expected type: String
+ */
+ CHANNEL_VOICE_STATUS("status"),
+
/**
* Change of the {@link ISlowmodeChannel#getSlowmode()} value.
*
diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java b/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java
index 681c1d15a0..4b069e77f7 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/channel/ChannelField.java
@@ -168,6 +168,14 @@ public enum ChannelField
* @see VoiceChannel#getUserLimit()
*/
USER_LIMIT("userlimit", AuditLogKey.CHANNEL_USER_LIMIT),
+ /**
+ * The status of the channel.
+ *
+ *
Limited to {@link VoiceChannel Voice Channels}.
+ *
+ * @see VoiceChannel#getStatus()
+ */
+ VOICE_STATUS("status", AuditLogKey.CHANNEL_VOICE_STATUS),
//Thread Specific
diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java b/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java
new file mode 100644
index 0000000000..47195b4eb4
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/api/entities/channel/attribute/IVoiceStatusChannel.java
@@ -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.
+ *
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.
+ *
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.
+ *
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
+ *
+ * - If the currently logged in account is not connected and does not have the {@link Permission#MANAGE_CHANNEL MANAGE_CHANNEL} permission.
+ * - If the currently logged in account is connected and does not have the {@link Permission#VOICE_SET_STATUS VOICE_SET_STATUS} permission.
+ *
+ *
+ * @return {@link AuditableRestAction}
+ */
+ @Nonnull
+ @CheckReturnValue
+ AuditableRestAction modifyStatus(@Nonnull String status);
+}
diff --git a/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java b/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java
index 7c18c463b5..d1c957c62c 100644
--- a/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java
+++ b/src/main/java/net/dv8tion/jda/api/entities/channel/concrete/VoiceChannel.java
@@ -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;
@@ -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})
diff --git a/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java b/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java
new file mode 100644
index 0000000000..de172cb414
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/api/events/channel/update/ChannelUpdateVoiceStatusEvent.java
@@ -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.
+ *
+ * Can be used to retrieve the old status and the new one.
+ *
+ *
Limited to {@link VoiceChannel VoiceChannels}.
+ *
+ * @see VoiceChannel#getStatus()
+ */
+public class ChannelUpdateVoiceStatusEvent extends GenericChannelUpdateEvent
+{
+ 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);
+ }
+}
diff --git a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java
index aa26bce27c..3df7247bae 100644
--- a/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java
+++ b/src/main/java/net/dv8tion/jda/api/hooks/ListenerAdapter.java
@@ -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) {}
diff --git a/src/main/java/net/dv8tion/jda/api/requests/Route.java b/src/main/java/net/dv8tion/jda/api/requests/Route.java
index e28e1ca5e1..f15462924c 100644
--- a/src/main/java/net/dv8tion/jda/api/requests/Route.java
+++ b/src/main/java/net/dv8tion/jda/api/requests/Route.java
@@ -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");
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
index 09b06f2ad8..cae8badde5 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/EntityBuilder.java
@@ -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"))
diff --git a/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java b/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java
index a9f3148599..b59ac14014 100644
--- a/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java
+++ b/src/main/java/net/dv8tion/jda/internal/entities/channel/concrete/VoiceChannelImpl.java
@@ -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;
@@ -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;
@@ -55,6 +59,7 @@ public class VoiceChannelImpl extends AbstractStandardGuildChannelImpl connectedMembers = MiscUtil.newLongMap();
private String region;
+ private String status = "";
private long latestMessageId;
private int bitrate;
private int userLimit;
@@ -162,6 +167,29 @@ public VoiceChannelManager getManager()
return new VoiceChannelManagerImpl(this);
}
+ @Nonnull
+ @Override
+ public String getStatus()
+ {
+ return status;
+ }
+
+ @Nonnull
+ @Override
+ public AuditableRestAction 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 getConnectedMembersMap()
{
@@ -210,6 +238,12 @@ public VoiceChannelImpl setLatestMessageIdLong(long latestMessageId)
return this;
}
+ public VoiceChannelImpl setStatus(String status)
+ {
+ this.status = status;
+ return this;
+ }
+
// -- Abstract Hooks --
@Override
diff --git a/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java b/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java
new file mode 100644
index 0000000000..a366e038f0
--- /dev/null
+++ b/src/main/java/net/dv8tion/jda/internal/handle/VoiceChannelStatusUpdateHandler.java
@@ -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;
+ }
+}
diff --git a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java
index aa02b8e52e..6225bc0463 100644
--- a/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java
+++ b/src/main/java/net/dv8tion/jda/internal/requests/WebSocketClient.java
@@ -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);