Skip to content

Commit

Permalink
feat(GuildMember): add per-guild avatars
Browse files Browse the repository at this point in the history
I opted by only adding the avatar property and the avatarURL function, as the display avatar will either be the server avatar or the user's displayavatar. If it makes it easier for development though, I can add the displayAvatarURL() function from User to GuildMember.

types(GuildMember): add avatar and avatarURL()

feat(GuildMember): add displayAvatarURL()

Also changed user -> member in the jsdocs

types(GuildMember): add displayAvatarURL()

Remove empty line

fix(GuildMember): fixed GuildAvatar format

types(Cdn): add GuildAvatar and AllowedImageSize types

Decided to specify the allowed image sizes in a type declaration since "number" was inaccurate.
Also for some reason husky wouldn't let me commit this as types(CDN) or types(cdn)

types(Cdn): fix format type

fix(GuildMember): rename GuildAvatar => GuildMemberAvatar

docs(GuildMember): link to User#displayAvatarURL

types(GuildMember): add AllowedImageSize back

fix(cdn): consistent casing of ID

fix(cdn): forgot to change these

types(Cdn): remove redundant image URL options

feat(GuildMember): add avatar to .equals()

feat(User): add avatar to toJSON()

Co-Authored-By: Shubham Parihar <shubhamparihar391@gmail.com>
  • Loading branch information
ImRodry and iShibi committed Jun 29, 2021
1 parent fb8d516 commit 0d10016
Show file tree
Hide file tree
Showing 3 changed files with 86 additions and 13 deletions.
35 changes: 34 additions & 1 deletion src/structures/GuildMember.js
Expand Up @@ -83,6 +83,15 @@ class GuildMember extends Base {
}

if ('nick' in data) this.nickname = data.nick;
if ('avatar' in data) {
/**
* The ID of the member's guild avatar
* @type {?string}
*/
this.avatar = data.avatar;
} else if (typeof this.avatar !== 'string') {
this.avatar = null;
}
if ('joined_at' in data) this.joinedTimestamp = new Date(data.joined_at).getTime();
if ('premium_since' in data) {
this.premiumSinceTimestamp = data.premium_since === null ? null : new Date(data.premium_since).getTime();
Expand Down Expand Up @@ -136,6 +145,26 @@ class GuildMember extends Base {
return this.guild.voiceStates.cache.get(this.id) || new VoiceState(this.guild, { user_id: this.id });
}

/**
* A link to the member's guild avatar.
* @param {ImageURLOptions} [options={}] Options for the Image URL
* @returns {?string}
*/
avatarURL({ format, size, dynamic } = {}) {
if (!this.avatar) return null;
return this.client.rest.cdn.GuildMemberAvatar(this.guild.id, this.id, this.avatar, format, size, dynamic);
}

/**
* A link to the member's guild avatar if they have one.
* Otherwise, a link to their {@link User#displayAvatarURL} will be returned.
* @param {ImageURLOptions} [options={}] Options for the Image URL
* @returns {string}
*/
displayAvatarURL(options) {
return this.avatarURL(options) || this.user.displayAvatarURL(options);
}

/**
* The time this member joined the guild
* @type {?Date}
Expand Down Expand Up @@ -361,6 +390,7 @@ class GuildMember extends Base {
this.lastMessageID === member.lastMessageID &&
this.lastMessageChannelID === member.lastMessageChannelID &&
this.nickname === member.nickname &&
this.avatar === member.avatar &&
this.pending === member.pending &&
(this._roles === member._roles ||
(this._roles.length === member._roles.length && this._roles.every((role, i) => role === member._roles[i])))
Expand All @@ -379,14 +409,17 @@ class GuildMember extends Base {
}

toJSON() {
return super.toJSON({
const json = super.toJSON({
guild: 'guildID',
user: 'userID',
displayName: true,
lastMessage: false,
lastMessageID: false,
roles: true,
});
json.avatarURL = this.avatarURL();
json.displayAvatarURL = this.displayAvatarURL();
return json;
}

// These are here only for documentation purposes - they are implemented by TextBasedChannel
Expand Down
4 changes: 4 additions & 0 deletions src/util/Constants.js
Expand Up @@ -159,6 +159,10 @@ exports.Endpoints = {
if (dynamic) format = hash.startsWith('a_') ? 'gif' : format;
return makeImageUrl(`${root}/avatars/${userID}/${hash}`, { format, size });
},
GuildMemberAvatar: (guildID, memberID, hash, format = 'webp', size, dynamic = false) => {
if (dynamic) format = hash.startsWith('a_') ? 'gif' : format;
return makeImageUrl(`${root}/guilds/${guildID}/users/${memberID}/avatars/${hash}`, { format, size });
},
Banner: (guildID, hash, format = 'webp', size) =>
makeImageUrl(`${root}/banners/${guildID}/${hash}`, { format, size }),
Icon: (guildID, hash, format = 'webp', size, dynamic = false) => {
Expand Down
60 changes: 48 additions & 12 deletions typings/index.d.ts
Expand Up @@ -548,6 +548,7 @@ declare module 'discord.js' {
}

type AllowedImageFormat = 'webp' | 'png' | 'jpg' | 'jpeg' | 'gif';
type AllowedImageSize = 16 | 32 | 64 | 128 | 256 | 512 | 1024 | 2048 | 4096;

export const Constants: {
Package: {
Expand Down Expand Up @@ -581,27 +582,59 @@ declare module 'discord.js' {
Avatar: (
userID: Snowflake | number,
hash: string,
format: 'default' | AllowedImageFormat,
size: number,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
GuildMemberAvatar: (
guildId: Snowflake | number,
userId: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
Banner: (
guildID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
Banner: (guildID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
Icon: (
Icon: (userID: Snowflake | number, hash: string, format: AllowedImageFormat, size: AllowedImageSize) => string;
AppIcon: (
userID: Snowflake | number,
hash: string,
format: 'default' | AllowedImageFormat,
size: number,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
AppAsset: (
userID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
GDMIcon: (
userID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
Splash: (
guildID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
AppIcon: (userID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
AppAsset: (userID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
GDMIcon: (userID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
Splash: (guildID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
DiscoverySplash: (
guildID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: number,
size: AllowedImageSize,
) => string;
TeamIcon: (
teamID: Snowflake | number,
hash: string,
format: AllowedImageFormat,
size: AllowedImageSize,
) => string;
TeamIcon: (teamID: Snowflake | number, hash: string, format: AllowedImageFormat, size: number) => string;
};
};
WSCodes: {
Expand Down Expand Up @@ -1037,6 +1070,7 @@ declare module 'discord.js' {
constructor(client: Client, data: unknown, guild: Guild);
public readonly bannable: boolean;
public deleted: boolean;
public avatar: string | null;
public readonly displayColor: number;
public readonly displayHexColor: string;
public readonly displayName: string;
Expand All @@ -1057,6 +1091,8 @@ declare module 'discord.js' {
public readonly roles: GuildMemberRoleManager;
public user: User;
public readonly voice: VoiceState;
public avatarURL(options?: ImageURLOptions): string | null;
public displayAvatarURL(options?: ImageURLOptions): string;
public ban(options?: BanOptions): Promise<GuildMember>;
public fetch(force?: boolean): Promise<GuildMember>;
public createDM(force?: boolean): Promise<DMChannel>;
Expand Down

0 comments on commit 0d10016

Please sign in to comment.