Skip to content
Open
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 10 additions & 1 deletion packages/structures/src/emojis/Emoji.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APIEmoji } from 'discord-api-types/v10';
import { CDNRoutes, ImageFormat, RouteBases, type APIEmoji, type EmojiFormat } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
Expand Down Expand Up @@ -85,4 +85,13 @@ export class Emoji<Omitted extends keyof APIEmoji | '' = ''> extends Structure<A
const createdTimestamp = this.createdTimestamp;
return createdTimestamp ? new Date(createdTimestamp) : null;
}

/**
* Get the URL to the emoji
*
* @param format - the file format to use
*/
public url(format: EmojiFormat = ImageFormat.WebP) {
return isIdSet(this[kData].id) ? `${RouteBases.cdn}${CDNRoutes.emoji(this[kData].id.toString(), format)}` : null;
}
}
26 changes: 25 additions & 1 deletion packages/structures/src/stickers/Sticker.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,23 @@
import type { APISticker } from 'discord-api-types/v10';
import {
CDNRoutes,
ImageFormat,
RouteBases,
StickerFormatType,
type APISticker,
type StickerFormat,
} from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData } from '../utils/symbols.js';
import { isFieldSet, isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

const StickerFormatExtensionMap = {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be exported to the consumer.
Maybe this should be moved to discord-api-types?

[StickerFormatType.PNG]: ImageFormat.PNG,
[StickerFormatType.APNG]: ImageFormat.PNG,
[StickerFormatType.Lottie]: ImageFormat.Lottie,
[StickerFormatType.GIF]: ImageFormat.GIF,
} satisfies Record<StickerFormatType, StickerFormat>;

/**
* Represents a sticker on Discord.
*
Expand Down Expand Up @@ -69,4 +84,13 @@ export class Sticker<Omitted extends keyof APISticker | '' = ''> extends Structu
public get type() {
return this[kData].type;
}

/**
* Get the URL to the sticker
*/
public get url() {
return isIdSet(this[kData].id) && isFieldSet(this[kData], 'format_type', 'number')
? `${RouteBases.cdn}${CDNRoutes.sticker(this[kData].id.toString(), StickerFormatExtensionMap[this[kData].format_type] as StickerFormat)}`
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not particularly fond of this cast... isEnumValue(this[kData].format_type, StickerFormatType) time? 😅

: null;
}
}
14 changes: 13 additions & 1 deletion packages/structures/src/users/AvatarDecorationData.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { APIAvatarDecorationData } from 'discord-api-types/v10';
import { CDNRoutes, RouteBases, type APIAvatarDecorationData } from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData } from '../utils/symbols.js';
import { isFieldSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

/**
Expand Down Expand Up @@ -37,4 +38,15 @@ export class AvatarDecorationData<Omitted extends keyof APIAvatarDecorationData
public get asset() {
return this[kData].asset;
}

/**
* Get the URL to the asset of this avatar decoration
*
* @returns the URL to the asset of this avatar decoration
Comment on lines +44 to +45
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

redundant

Suggested change
*
* @returns the URL to the asset of this avatar decoration

*/
public assetURL() {
return isFieldSet(this[kData], 'asset', 'string')
? `${RouteBases.cdn}${CDNRoutes.avatarDecoration(this[kData].asset)}`
: null;
}
}
54 changes: 52 additions & 2 deletions packages/structures/src/users/User.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,16 @@
import { DiscordSnowflake } from '@sapphire/snowflake';
import type { APIUser } from 'discord-api-types/v10';
import {
CDNRoutes,
ImageFormat,
RouteBases,
type APIUser,
type DefaultUserAvatarAssets,
type UserAvatarFormat,
type UserBannerFormat,
} from 'discord-api-types/v10';
import { Structure } from '../Structure.js';
import { kData } from '../utils/symbols.js';
import { isIdSet } from '../utils/type-guards.js';
import { isFieldSet, isIdSet } from '../utils/type-guards.js';
import type { Partialize } from '../utils/types.js';

/**
Expand Down Expand Up @@ -66,6 +74,37 @@ export class User<Omitted extends keyof APIUser | '' = ''> extends Structure<API
return this[kData].avatar;
}

/**
* Get the URL to the user avatar
*
* @param format - the file format to use
*/
public avatarURL(format: UserAvatarFormat = ImageFormat.WebP) {
return isIdSet(this[kData].id) && isFieldSet(this[kData], 'avatar', 'string')
? `${RouteBases.cdn}${CDNRoutes.userAvatar(this[kData].id.toString(), this[kData].avatar, format)}`
: null;
}

/**
* Get the URL to the user's default avatar
*/
public get defaultAvatarURL() {
return isIdSet(this[kData].id)
? `${RouteBases.cdn}${CDNRoutes.defaultUserAvatar(
(isFieldSet(this[kData], 'discriminator', 'string') && this[kData].discriminator.length === 4
? Number(this[kData].discriminator) % 5
: Number(BigInt(this[kData].id) >> 22n) % 6) as DefaultUserAvatarAssets,
)}`
Comment on lines +93 to +97
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Too much logic here IMO. I'd rather split this up a bit

: null;
}

/**
* Get the URL to the user avatar or their default avatar, if none is set
*/
public displayAvatarURL(format: UserAvatarFormat = ImageFormat.WebP) {
return this.avatarURL(format) ?? this.defaultAvatarURL;
}

/**
* Whether the user is a bot
*/
Expand Down Expand Up @@ -98,6 +137,17 @@ export class User<Omitted extends keyof APIUser | '' = ''> extends Structure<API
return this[kData].banner;
}

/**
* Get the URL to the user banner
*
* @param format - the file format to use
*/
public bannerURL(format: UserBannerFormat = ImageFormat.WebP) {
return isIdSet(this[kData].id) && isFieldSet(this[kData], 'banner', 'string')
? `${RouteBases.cdn}${CDNRoutes.userBanner(this[kData].id.toString(), this[kData].banner, format)}`
: null;
}

/**
* The base 10 accent color of the user's banner
*
Expand Down