Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Application Emoji #2726

Merged
54 changes: 54 additions & 0 deletions src/main/java/net/dv8tion/jda/api/JDA.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import net.dv8tion.jda.api.entities.channel.concrete.PrivateChannel;
import net.dv8tion.jda.api.entities.channel.concrete.TextChannel;
import net.dv8tion.jda.api.entities.channel.middleman.MessageChannel;
import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.sticker.*;
import net.dv8tion.jda.api.events.GenericEvent;
Expand Down Expand Up @@ -1750,6 +1751,59 @@ default List<RichCustomEmoji> getEmojisByName(@Nonnull String name, boolean igno
return getEmojiCache().getElementsByName(name, ignoreCase);
}

/**
* Creates a new {@link ApplicationEmoji} for this bot.
*
* <p>Note that the bot is limited to {@value ApplicationEmoji#APPLICATION_EMOJI_CAP} Application Emojis (normal and animated).
*
* @param name
* The name for the new emoji (2-{@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters)
* @param icon
* The {@link Icon} for the new emoji
*/
@Nonnull
@CheckReturnValue
RestAction<ApplicationEmoji> createApplicationEmoji(@Nonnull String name, @Nonnull Icon icon);
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved

/**
* Retrieves a list of Application Emojis together with their respective creators.
*
* @return {@link RestAction RestAction} - Type: List of {@link ApplicationEmoji}
*/
@Nonnull
@CheckReturnValue
RestAction<List<ApplicationEmoji>> retrieveApplicationEmojis();

/**
* Retrieves an application emoji together with its respective creator.
*
* @param emojiId
* The emoji id
*
* @return {@link RestAction RestAction} - Type: {@link ApplicationEmoji}
*/
@Nonnull
@CheckReturnValue
default RestAction<ApplicationEmoji> retrieveApplicationEmojiById(long emojiId)
{
return retrieveApplicationEmojiById(Long.toUnsignedString(emojiId));
}

/**
* Retrieves an application emoji together with its respective creator.
yoyosource marked this conversation as resolved.
Show resolved Hide resolved
*
* @param emojiId
* The emoji id
*
* @throws IllegalArgumentException
* If the provided id is not a valid snowflake
*
* @return {@link RestAction RestAction} - Type: {@link ApplicationEmoji}
*/
@Nonnull
@CheckReturnValue
RestAction<ApplicationEmoji> retrieveApplicationEmojiById(@Nonnull String emojiId);

/**
* Attempts to retrieve a {@link Sticker} object based on the provided snowflake reference.
* <br>This works for both {@link StandardSticker} and {@link GuildSticker}, and you can resolve them using the provided {@link StickerUnion}.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
/*
* Copyright 2024 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.emoji;

import net.dv8tion.jda.api.JDA;
import net.dv8tion.jda.api.entities.Icon;
import net.dv8tion.jda.api.entities.User;
import net.dv8tion.jda.api.managers.ApplicationEmojiManager;
import net.dv8tion.jda.api.requests.RestAction;

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

/**
* Represents a Custom Emoji hosted on the Bot Account.
*
* <p><b>This does not represent unicode emojis like they are used in the official client!
* The format {@code :smiley:} is a client-side alias which is replaced by the unicode emoji, not a custom emoji.</b>
*
* @see JDA#createApplicationEmoji(String, Icon)
* @see JDA#retrieveApplicationEmojiById(long)
* @see JDA#retrieveApplicationEmojis()
*/
public interface ApplicationEmoji extends CustomEmoji
{
int APPLICATION_EMOJI_CAP = 2000;

/**
* The {@link net.dv8tion.jda.api.JDA JDA} instance of this emoji
*
* @return The JDA instance of this emoji
*/
@Nonnull
JDA getJDA();

/**
* The user who created this emoji
*
* @return The user who created this emoji
*/
@Nullable
User getOwner();

/**
* Deletes this emoji.
*
* <p>Possible ErrorResponses include:
* <ul>
* <li>{@link net.dv8tion.jda.api.requests.ErrorResponse#UNKNOWN_EMOJI UNKNOWN_EMOJI}
* <br>If this emoji was already removed</li>
* </ul>
*
* @return {@link net.dv8tion.jda.api.requests.RestAction RestAction}
* The RestAction to delete this emoji.
*/
@Nonnull
@CheckReturnValue
RestAction<Void> delete();

/**
* The {@link ApplicationEmojiManager Manager} for this emoji, used to modify
* properties of the emoji like name.
*
* @return The ApplicationEmojiManager for this emoji
*/
@Nonnull
@CheckReturnValue
ApplicationEmojiManager getManager();
}
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@
*/
public interface CustomEmoji extends Emoji, IMentionable
{
int EMOJI_NAME_MAX_LENGTH = 32
MinnDevelopment marked this conversation as resolved.
Show resolved Hide resolved

/** Template for {@link #getImageUrl()} */
String ICON_URL = "https://cdn.discordapp.com/emojis/%s.%s";

Expand Down
3 changes: 2 additions & 1 deletion src/main/java/net/dv8tion/jda/api/entities/emoji/Emoji.java
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,9 @@ enum Type
*/
UNICODE,
/**
* Custom Guild Emoji.
* Custom Guild Emoji or Custom Application Emoji.
* <br>This represents emojis which were created by users and added to a guild.
* <br>This can also represent emojis which were created and owned by a specific application.
*/
CUSTOM,
yoyosource marked this conversation as resolved.
Show resolved Hide resolved
}
Expand Down
25 changes: 24 additions & 1 deletion src/main/java/net/dv8tion/jda/api/entities/emoji/EmojiUnion.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
* Represents possible {@link Emoji} types.
*
* <p>This delegates the emoji methods for some concrete emoji type,
* but can be converted to a concrete type using either {@link #asUnicode()} or {@link #asCustom()}.
* but can be converted to a concrete type using either {@link #asUnicode()},
* {@link #asCustom()}, {@link #asRich()} or {@link #asApplication()}.
*/
public interface EmojiUnion extends Emoji
{
Expand All @@ -47,4 +48,26 @@ public interface EmojiUnion extends Emoji
*/
@Nonnull
CustomEmoji asCustom();

/**
* Returns the underlying {@link RichCustomEmoji} if applicable.
*
* @throws IllegalStateException
* If this is not a {@link RichCustomEmoji}
*
* @return The {@link RichCustomEmoji}
*/
@Nonnull
RichCustomEmoji asRich();

/**
* Returns the underlying {@link ApplicationEmoji} if applicable.
*
* @throws IllegalStateException
* If this is not a {@link ApplicationEmoji}
*
* @return The {@link ApplicationEmoji}
*/
@Nonnull
ApplicationEmoji asApplication();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/*
* Copyright 2024 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.managers;
yoyosource marked this conversation as resolved.
Show resolved Hide resolved

import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;

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

/**
* Manager providing functionality to update the name field for an {@link ApplicationEmoji}.
*
* <p><b>Example</b>
* <pre>{@code
* manager.setName("minn")
* .queue();
* }</pre>
*
* @see ApplicationEmoji#getManager()
*/
public interface ApplicationEmojiManager extends Manager<ApplicationEmojiManager>
{
/** Used to reset the name field */
long NAME = 1;

/**
* Resets the fields specified by the provided bit-flag pattern.
* You can specify a combination by using a bitwise OR concat of the flag constants.
*
* <p><b>Flag Constants:</b>
* <ul>
* <li>{@link #NAME}</li>
* </ul>
*
* @param fields
* Integer value containing the flags to reset.
*
* @return ApplicationEmojiManager for chaining convenience.
*/
@Nonnull
@Override
ApplicationEmojiManager reset(long fields);

/**
* Resets the fields specified by the provided bit-flag patterns.
*
* <p><b>Flag Constants:</b>
* <ul>
* <li>{@link #NAME}</li>
* </ul>
*
* @param fields
* Integer values containing the flags to reset.
*
* @return ApplicationEmojiManager for chaining convenience.
*/
@Nonnull
@Override
ApplicationEmojiManager reset(long... fields);

/**
* The target {@link ApplicationEmoji} that will be modified by this Manager
*
* @return The target emoji
*/
@Nonnull
ApplicationEmoji getEmoji();

/**
* Sets the <b><u>name</u></b> of the selected {@link ApplicationEmoji}.
*
* <p>An emoji name <b>must</b> be between 2-{@value CustomEmoji#EMOJI_NAME_MAX_LENGTH} characters long!
* <br>Emoji names may only be populated with alphanumeric (with underscore and dash).
*
* <p><b>Example</b>: {@code tatDab} or {@code fmgSUP}
*
* @param name
* The new name for the selected {@link ApplicationEmoji}
*
* @return ApplicationEmojiManager for chaining convenience.
*/
@Nonnull
@CheckReturnValue
ApplicationEmojiManager setName(@Nonnull String name);
}
5 changes: 5 additions & 0 deletions src/main/java/net/dv8tion/jda/api/requests/Route.java
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ public static class Applications
public static final Route CONSUME_ENTITLEMENT = new Route(POST, "applications/{application_id}/entitlements/{entitlement_id}/consume");
public static final Route CREATE_TEST_ENTITLEMENT = new Route(POST, "applications/{application_id}/entitlements");
public static final Route DELETE_TEST_ENTITLEMENT = new Route(DELETE, "applications/{application_id}/entitlements/{entitlement_id}");
public static final Route GET_APPLICATION_EMOJIS = new Route(GET, "applications/{application_id}/emojis");
public static final Route GET_APPLICATION_EMOJI = new Route(GET, "applications/{application_id}/emojis/{emoji_id}");
public static final Route CREATE_APPLICATION_EMOJI = new Route(POST, "applications/{application_id}/emojis");
public static final Route MODIFY_APPLICATION_EMOJI = new Route(PATCH, "applications/{application_id}/emojis/{emoji_id}");
public static final Route DELETE_APPLICATION_EMOJI = new Route(DELETE, "applications/{application_id}/emojis/{emoji_id}");
}

public static class Interactions
Expand Down
49 changes: 49 additions & 0 deletions src/main/java/net/dv8tion/jda/internal/JDAImpl.java
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
import net.dv8tion.jda.api.entities.channel.ChannelType;
import net.dv8tion.jda.api.entities.channel.concrete.*;
import net.dv8tion.jda.api.entities.channel.middleman.GuildChannel;
import net.dv8tion.jda.api.entities.emoji.ApplicationEmoji;
import net.dv8tion.jda.api.entities.emoji.RichCustomEmoji;
import net.dv8tion.jda.api.entities.sticker.StickerPack;
import net.dv8tion.jda.api.entities.sticker.StickerSnowflake;
Expand Down Expand Up @@ -675,6 +676,54 @@ public SnowflakeCacheView<RichCustomEmoji> getEmojiCache()
return CacheView.allSnowflakes(() -> guildCache.stream().map(Guild::getEmojiCache));
}

@Nonnull
@Override
public RestAction<ApplicationEmoji> createApplicationEmoji(@Nonnull String name, @Nonnull Icon icon)
{
Checks.inRange(name, 2, CustomEmoji.EMOJI_NAME_MAX_LENGTH, "Emoji name");
Checks.notNull(icon, "Emoji icon");

DataObject body = DataObject.empty();
body.put("name", name);
body.put("image", icon.getEncoding());

final Route.CompiledRoute route = Route.Applications.CREATE_APPLICATION_EMOJI.compile(getSelfUser().getApplicationId());
return new RestActionImpl<>(this, route, body, (response, request) ->
{
final DataObject obj = response.getObject();
return entityBuilder.createApplicationEmoji(this, obj);
});
}

@Nonnull
@Override
public RestAction<List<ApplicationEmoji>> retrieveApplicationEmojis()
{
Route.CompiledRoute route = Route.Applications.GET_APPLICATION_EMOJIS.compile(getSelfUser().getApplicationId());
return new RestActionImpl<>(this, route, (response, request) ->
{
DataArray emojis = response.getObject().getArray("items");
List<ApplicationEmoji> list = new ArrayList<>(emojis.length());
for (int i = 0; i < emojis.length(); i++)
{
list.add(entityBuilder.createApplicationEmoji(this, emojis.getObject(i)));
}

return Collections.unmodifiableList(list);
});
}

@Nonnull
@Override
public RestAction<ApplicationEmoji> retrieveApplicationEmojiById(@Nonnull String emojiId)
yoyosource marked this conversation as resolved.
Show resolved Hide resolved
{
Checks.isSnowflake(emojiId);
Route.CompiledRoute route = Route.Applications.GET_APPLICATION_EMOJI.compile(getSelfUser().getApplicationId(), emojiId);
return new RestActionImpl<>(this, route,
(response, request) -> entityBuilder.createApplicationEmoji(this, response.getObject())
);
}

@Nonnull
@Override
public RestAction<StickerUnion> retrieveSticker(@Nonnull StickerSnowflake sticker)
Expand Down
Loading
Loading