Merge pull request #703 from aiko-chan-ai/new-username

#9634 djs
This commit is contained in:
Elysia 2023-06-14 14:01:29 +07:00 committed by GitHub
commit e14e04d2ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 61 additions and 10 deletions

View File

@ -321,12 +321,12 @@ class GuildMember extends Base {
} }
/** /**
* The nickname of this member, or their username if they don't have one * The nickname of this member, or their user display name if they don't have one
* @type {?string} * @type {?string}
* @readonly * @readonly
*/ */
get displayName() { get displayName() {
return this.nickname ?? this.user.username; return this.nickname ?? this.user.displayName;
} }
/** /**

View File

@ -1,5 +1,6 @@
'use strict'; 'use strict';
const process = require('node:process');
const { Collection } = require('@discordjs/collection'); const { Collection } = require('@discordjs/collection');
const Base = require('./Base'); const Base = require('./Base');
const ClientApplication = require('./ClientApplication'); const ClientApplication = require('./ClientApplication');
@ -9,6 +10,9 @@ const { Error } = require('../errors');
const { RelationshipTypes, NitroType } = require('../util/Constants'); const { RelationshipTypes, NitroType } = require('../util/Constants');
const SnowflakeUtil = require('../util/SnowflakeUtil'); const SnowflakeUtil = require('../util/SnowflakeUtil');
const UserFlags = require('../util/UserFlags'); const UserFlags = require('../util/UserFlags');
const Util = require('../util/Util');
let tagDeprecationEmitted = false;
/** /**
* Represents a user on Discord. * Represents a user on Discord.
@ -94,6 +98,16 @@ class User extends Base {
this.username ??= null; this.username ??= null;
} }
if ('global_name' in data) {
/**
* The global name of this user
* @type {?string}
*/
this.globalName = data.global_name;
} else {
this.globalName ??= null;
}
if ('bot' in data) { if ('bot' in data) {
/** /**
* Whether or not the user is a bot * Whether or not the user is a bot
@ -110,7 +124,8 @@ class User extends Base {
if ('discriminator' in data) { if ('discriminator' in data) {
/** /**
* A discriminator based on username for the user * The discriminator of this user
* <info>`'0'`, or a 4-digit stringified number if they're using the legacy username system</info>
* @type {?string} * @type {?string}
*/ */
this.discriminator = data.discriminator; this.discriminator = data.discriminator;
@ -453,7 +468,8 @@ class User extends Base {
* @readonly * @readonly
*/ */
get defaultAvatarURL() { get defaultAvatarURL() {
return this.client.rest.cdn.DefaultAvatar(this.discriminator % 5); const index = this.discriminator === '0' ? Util.calculateUserDefaultAvatarIndex(this.id) : this.discriminator % 5;
return this.client.rest.cdn.DefaultAvatar(index);
} }
/** /**
@ -527,12 +543,32 @@ class User extends Base {
} }
/** /**
* The Discord "tag" (e.g. `hydrabolt#0001`) for this user * The tag of this user
* <info>This user's username, or their legacy tag (e.g. `hydrabolt#0001`)
* if they're using the legacy username system</info>
* @type {?string} * @type {?string}
* @deprecated Use {@link User#username} instead.
* @readonly * @readonly
*/ */
get tag() { get tag() {
return typeof this.username === 'string' ? `${this.username}#${this.discriminator}` : null; if (!tagDeprecationEmitted) {
process.emitWarning('User#tag is deprecated. Use User#username instead.', 'DeprecationWarning');
tagDeprecationEmitted = true;
}
return typeof this.username === 'string'
? this.discriminator === '0'
? this.username
: `${this.username}#${this.discriminator}`
: null;
}
/**
* The global name of this user, or their username if they don't have one
* @type {?string}
* @readonly
*/
get displayName() {
return this.globalName ?? this.username;
} }
/** /**
@ -574,6 +610,7 @@ class User extends Base {
this.id === user.id && this.id === user.id &&
this.username === user.username && this.username === user.username &&
this.discriminator === user.discriminator && this.discriminator === user.discriminator &&
this.globalName === user.globalName &&
this.avatar === user.avatar && this.avatar === user.avatar &&
this.flags?.bitfield === user.flags?.bitfield && this.flags?.bitfield === user.flags?.bitfield &&
this.banner === user.banner && this.banner === user.banner &&
@ -594,6 +631,7 @@ class User extends Base {
this.id === user.id && this.id === user.id &&
this.username === user.username && this.username === user.username &&
this.discriminator === user.discriminator && this.discriminator === user.discriminator &&
this.globalName === user.global_name &&
this.avatar === user.avatar && this.avatar === user.avatar &&
this.flags?.bitfield === user.public_flags && this.flags?.bitfield === user.public_flags &&
('banner' in user ? this.banner === user.banner : true) && ('banner' in user ? this.banner === user.banner : true) &&

View File

@ -186,7 +186,7 @@ exports.Endpoints = {
return { return {
Emoji: (emojiId, format = 'webp') => `${root}/emojis/${emojiId}.${format}`, Emoji: (emojiId, format = 'webp') => `${root}/emojis/${emojiId}.${format}`,
Asset: name => `${root}/assets/${name}`, Asset: name => `${root}/assets/${name}`,
DefaultAvatar: discriminator => `${root}/embed/avatars/${discriminator}.png`, DefaultAvatar: index => `${root}/embed/avatars/${index}.png`,
Avatar: (userId, hash, format, size, dynamic = false) => { Avatar: (userId, hash, format, size, dynamic = false) => {
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 });

View File

@ -709,8 +709,8 @@ class Util extends null {
if (!files.length) return []; if (!files.length) return [];
files = files.map((file, i) => ({ files = files.map((file, i) => ({
filename: file.name ?? file.attachment?.name ?? file.attachment?.filename ?? 'file.jpg', filename: file.name ?? file.attachment?.name ?? file.attachment?.filename ?? 'file.jpg',
// 8MB = 8388608 bytes // 25MB = 26_214_400bytes
file_size: Math.floor((8_388_608 / 10) * Math.random()), file_size: Math.floor((26_214_400 / 10) * Math.random()),
id: `${i}`, id: `${i}`,
})); }));
const { attachments } = await client.api.channels[channelId].attachments.post({ const { attachments } = await client.api.channels[channelId].attachments.post({
@ -733,6 +733,15 @@ class Util extends null {
return false; return false;
} }
} }
/**
* Calculates the default avatar index for a given user id.
* @param {Snowflake} userId - The user id to calculate the default avatar index for
* @returns {number}
*/
static calculateUserDefaultAvatarIndex(userId) {
return Number(BigInt(userId) >> 22n) % 6;
}
} }
module.exports = Util; module.exports = Util;

6
typings/index.d.ts vendored
View File

@ -3260,14 +3260,17 @@ export class User extends PartialTextBasedChannel(Base) {
public readonly relationships: RelationshipTypes; public readonly relationships: RelationshipTypes;
public readonly createdTimestamp: number; public readonly createdTimestamp: number;
public discriminator: string; public discriminator: string;
public readonly displayName: string;
public readonly defaultAvatarURL: string; public readonly defaultAvatarURL: string;
public readonly dmChannel: DMChannel | null; public readonly dmChannel: DMChannel | null;
public flags: Readonly<UserFlags> | null; public flags: Readonly<UserFlags> | null;
public globalName: string | null;
public botInGuildsCount: number | null | undefined; public botInGuildsCount: number | null | undefined;
public readonly hexAccentColor: HexColorString | null | undefined; public readonly hexAccentColor: HexColorString | null | undefined;
public id: Snowflake; public id: Snowflake;
public readonly partial: false; public readonly partial: false;
public system: boolean; public system: boolean;
/** @deprecated Use {@link User#username} instead. */
public readonly tag: string; public readonly tag: string;
public username: string; public username: string;
public readonly note: string | null; public readonly note: string | null;
@ -3363,6 +3366,7 @@ export class Util extends null {
public static splitMessage(text: string, options?: SplitOptions): string[]; public static splitMessage(text: string, options?: SplitOptions): string[];
/** @deprecated This will be removed in the next major version. */ /** @deprecated This will be removed in the next major version. */
public static resolveAutoArchiveMaxLimit(guild: Guild): Exclude<ThreadAutoArchiveDuration, 60>; public static resolveAutoArchiveMaxLimit(guild: Guild): Exclude<ThreadAutoArchiveDuration, 60>;
public static calculateUserDefaultAvatarIndex(userId: Snowflake): number;
} }
export class Formatters extends null { export class Formatters extends null {
@ -3658,7 +3662,7 @@ export const Constants: {
dynamic: boolean, dynamic: boolean,
): 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(discriminator: number): string; DefaultAvatar(index: number): string;
DiscoverySplash(guildId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string; DiscoverySplash(guildId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string;
Emoji(emojiId: Snowflake, format: DynamicImageFormat): string; Emoji(emojiId: Snowflake, format: DynamicImageFormat): string;
GDMIcon(channelId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string; GDMIcon(channelId: Snowflake, hash: string, format: AllowedImageFormat, size: AllowedImageSize): string;