feat(GuildMember): add avatarDecorationData

backport #10942
This commit is contained in:
Elysia
2025-07-08 21:20:11 +07:00
parent 6f4ac78c7a
commit 55265d82d3
4 changed files with 43 additions and 9 deletions

View File

@@ -120,6 +120,19 @@ class GuildMember extends Base {
} else { } else {
this.flags ??= new GuildMemberFlags().freeze(); this.flags ??= new GuildMemberFlags().freeze();
} }
if (data.avatar_decoration_data) {
/**
* The member avatar decoration's data
* @type {?AvatarDecorationData}
*/
this.avatarDecorationData = {
asset: data.avatar_decoration_data.asset,
skuId: data.avatar_decoration_data.sku_id,
};
} else {
this.avatarDecorationData = null;
}
} }
_clone() { _clone() {
@@ -185,6 +198,15 @@ class GuildMember extends Base {
return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id }); return this.guild.voiceStates.cache.get(this.id) ?? new VoiceState(this.guild, { user_id: this.id });
} }
/**
* A link to the user's avatar decoration.
* @returns {?string}
*/
avatarDecorationURL() {
if (!this.avatarDecorationData) return null;
return this.client.rest.cdn.AvatarDecoration(this.avatarDecorationData.asset);
}
/** /**
* A link to the member's guild avatar. * A link to the member's guild avatar.
* @param {ImageURLOptions} [options={}] Options for the Image URL * @param {ImageURLOptions} [options={}] Options for the Image URL
@@ -206,6 +228,15 @@ class GuildMember extends Base {
); );
} }
/**
* A link to the member's guild avatar decoration if they have one.
* Otherwise, a link to their {@link User#avatarDecorationURL} will be returned.
* @returns {?string}
*/
displayAvatarDecorationURL() {
return this.avatarDecorationURL() ?? this.user.avatarDecorationURL();
}
/** /**
* A link to the member's guild avatar if they have one. * A link to the member's guild avatar if they have one.
* Otherwise, a link to their {@link User#displayAvatarURL} will be returned. * Otherwise, a link to their {@link User#displayAvatarURL} will be returned.
@@ -520,7 +551,9 @@ class GuildMember extends Base {
this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp && this.communicationDisabledUntilTimestamp === member.communicationDisabledUntilTimestamp &&
this.flags.equals(member.flags) && this.flags.equals(member.flags) &&
(this._roles === member._roles || (this._roles === member._roles ||
(this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i]))) (this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i]))) &&
this.avatarDecorationData?.asset === member.avatarDecorationData?.asset &&
this.avatarDecorationData?.skuId === member.avatarDecorationData?.skuId
); );
} }
@@ -546,6 +579,7 @@ class GuildMember extends Base {
json.bannerURL = this.bannerURL(); json.bannerURL = this.bannerURL();
json.displayAvatarURL = this.displayAvatarURL(); json.displayAvatarURL = this.displayAvatarURL();
json.displayBannerURL = this.displayBannerURL(); json.displayBannerURL = this.displayBannerURL();
json.avatarDecorationURL = this.avatarDecorationURL();
return json; return json;
} }

View File

@@ -238,13 +238,11 @@ class User extends Base {
/** /**
* A link to the user's avatar decoration. * A link to the user's avatar decoration.
* @param {StaticImageURLOptions} [options={}] Options for the image URL
* <info> The `format` option is not supported for this image URL</info>
* @returns {?string} * @returns {?string}
*/ */
avatarDecorationURL({ size } = {}) { avatarDecorationURL() {
if (!this.avatarDecorationData) return null; if (!this.avatarDecorationData) return null;
return this.client.rest.cdn.AvatarDecoration(this.avatarDecorationData.asset, size); return this.client.rest.cdn.AvatarDecoration(this.avatarDecorationData.asset);
} }
/** /**

View File

@@ -96,8 +96,7 @@ exports.Endpoints = {
if (dynamic && hash.startsWith('a_')) format = 'gif'; if (dynamic && hash.startsWith('a_')) format = 'gif';
return makeImageUrl(`${root}/avatars/${userId}/${hash}`, { format, size }); return makeImageUrl(`${root}/avatars/${userId}/${hash}`, { format, size });
}, },
AvatarDecoration: (hash, size) => AvatarDecoration: hash => makeImageUrl(`${root}/avatar-decoration-presets/${hash}`, { format: 'png' }),
makeImageUrl(`${root}/avatar-decoration-presets/${hash}`, { format: 'png', size }),
ClanBadge: (guildId, hash) => `${root}/clan-badges/${guildId}/${hash}.png`, ClanBadge: (guildId, hash) => `${root}/clan-badges/${guildId}/${hash}.png`,
GuildMemberAvatar: (guildId, memberId, hash, format = 'webp', size, dynamic = false) => { GuildMemberAvatar: (guildId, memberId, hash, format = 'webp', size, dynamic = false) => {
if (dynamic && hash.startsWith('a_')) format = 'gif'; if (dynamic && hash.startsWith('a_')) format = 'gif';

7
typings/index.d.ts vendored
View File

@@ -1702,6 +1702,7 @@ export class GuildMember extends PartialTextBasedChannel(Base) {
private constructor(client: Client, data: RawGuildMemberData, guild: Guild); private constructor(client: Client, data: RawGuildMemberData, guild: Guild);
private _roles: Snowflake[]; private _roles: Snowflake[];
public avatar: string | null; public avatar: string | null;
public avatarDecorationData: AvatarDecorationData | null;
public banner: string | null; public banner: string | null;
public readonly bannable: boolean; public readonly bannable: boolean;
/** @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091 */ /** @deprecated This will be removed in the next major version, see https://github.com/discordjs/discord.js/issues/7091 */
@@ -1730,6 +1731,7 @@ export class GuildMember extends PartialTextBasedChannel(Base) {
public user: User; public user: User;
public readonly voice: VoiceState; public readonly voice: VoiceState;
public avatarURL(options?: ImageURLOptions): string | null; public avatarURL(options?: ImageURLOptions): string | null;
public avatarDecorationURL(): string | null;
public bannerURL(options?: ImageURLOptions): string | null; public bannerURL(options?: ImageURLOptions): string | null;
public ban(options?: BanOptions): Promise<GuildMember>; public ban(options?: BanOptions): Promise<GuildMember>;
public disableCommunicationUntil(timeout: DateResolvable | null, reason?: string): Promise<GuildMember>; public disableCommunicationUntil(timeout: DateResolvable | null, reason?: string): Promise<GuildMember>;
@@ -1739,6 +1741,7 @@ export class GuildMember extends PartialTextBasedChannel(Base) {
public deleteDM(): Promise<DMChannel>; public deleteDM(): Promise<DMChannel>;
public displayAvatarURL(options?: ImageURLOptions): string; public displayAvatarURL(options?: ImageURLOptions): string;
public displayBannerURL(options?: ImageURLOptions): string | null; public displayBannerURL(options?: ImageURLOptions): string | null;
public displayAvatarDecorationURL(): string | null;
public edit(data: GuildMemberEditData, reason?: string): Promise<GuildMember>; public edit(data: GuildMemberEditData, reason?: string): Promise<GuildMember>;
public isCommunicationDisabled(): this is GuildMember & { public isCommunicationDisabled(): this is GuildMember & {
communicationDisabledUntilTimestamp: number; communicationDisabledUntilTimestamp: number;
@@ -3662,7 +3665,7 @@ export class User extends PartialTextBasedChannel(Base) {
/** @deprecated Use {@link User.primaryGuild} instead */ /** @deprecated Use {@link User.primaryGuild} instead */
public clan: PrimaryGuild | null; public clan: PrimaryGuild | null;
public avatarURL(options?: ImageURLOptions): string | null; public avatarURL(options?: ImageURLOptions): string | null;
public avatarDecorationURL(options?: Omit<StaticImageURLOptions, 'format'>): string | null; public avatarDecorationURL(): string | null;
public bannerURL(options?: ImageURLOptions): string | null; public bannerURL(options?: ImageURLOptions): string | null;
public clanBadgeURL(): string | null; public clanBadgeURL(): string | null;
public createDM(force?: boolean): Promise<DMChannel>; public createDM(force?: boolean): Promise<DMChannel>;
@@ -4065,7 +4068,7 @@ export const Constants: {
size: AllowedImageSize, size: AllowedImageSize,
dynamic: boolean, dynamic: boolean,
): string; ): string;
AvatarDecoration(hash: string, size: AllowedImageSize): string; AvatarDecoration(hash: string): string;
ClanBadge(guildId: Snowflake, hash: string): string; ClanBadge(guildId: Snowflake, hash: string): string;
Banner(id: Snowflake, hash: string, format: DynamicImageFormat, size: AllowedImageSize, dynamic: boolean): string; Banner(id: Snowflake, hash: string, format: DynamicImageFormat, size: AllowedImageSize, dynamic: boolean): string;
DefaultAvatar(index: number): string; DefaultAvatar(index: number): string;