From 0951309b32edf397d88dcdd8fc5da934d514e64e Mon Sep 17 00:00:00 2001 From: Suneet Tipirneni <77477100+suneettipirneni@users.noreply.github.com> Date: Mon, 17 Jan 2022 07:14:03 -0500 Subject: [PATCH] chore(cdn): default to animated images (#7265) Co-authored-by: Jiralite <33201955+Jiralite@users.noreply.github.com> Co-authored-by: Almeida --- packages/rest/__tests__/CDN.test.ts | 46 ++++++++++++++--------------- packages/rest/src/lib/CDN.ts | 44 +++++++++++++++++++++++---- 2 files changed, 60 insertions(+), 30 deletions(-) diff --git a/packages/rest/__tests__/CDN.test.ts b/packages/rest/__tests__/CDN.test.ts index 9eec365ff..2c240c560 100644 --- a/packages/rest/__tests__/CDN.test.ts +++ b/packages/rest/__tests__/CDN.test.ts @@ -9,43 +9,43 @@ const defaultAvatar = 1234 % 5; const cdn = new CDN(base); test('appAsset default', () => { - expect(cdn.appAsset(id, hash)).toBe(`${base}/app-assets/${id}/${hash}.png`); + expect(cdn.appAsset(id, hash)).toBe(`${base}/app-assets/${id}/${hash}.webp`); }); test('appIcon default', () => { - expect(cdn.appIcon(id, hash)).toBe(`${base}/app-icons/${id}/${hash}.png`); + expect(cdn.appIcon(id, hash)).toBe(`${base}/app-icons/${id}/${hash}.webp`); }); test('avatar default', () => { - expect(cdn.avatar(id, hash)).toBe(`${base}/avatars/${id}/${hash}.png`); + expect(cdn.avatar(id, hash)).toBe(`${base}/avatars/${id}/${hash}.webp`); }); test('avatar dynamic-animated', () => { - expect(cdn.avatar(id, animatedHash, { dynamic: true })).toBe(`${base}/avatars/${id}/${animatedHash}.gif`); + expect(cdn.avatar(id, animatedHash)).toBe(`${base}/avatars/${id}/${animatedHash}.gif`); }); test('avatar dynamic-not-animated', () => { - expect(cdn.avatar(id, hash, { dynamic: true })).toBe(`${base}/avatars/${id}/${hash}.png`); + expect(cdn.avatar(id, hash)).toBe(`${base}/avatars/${id}/${hash}.webp`); }); test('banner default', () => { - expect(cdn.banner(id, hash)).toBe(`${base}/banners/${id}/${hash}.png`); + expect(cdn.banner(id, hash)).toBe(`${base}/banners/${id}/${hash}.webp`); }); test('channelIcon default', () => { - expect(cdn.channelIcon(id, hash)).toBe(`${base}/channel-icons/${id}/${hash}.png`); + expect(cdn.channelIcon(id, hash)).toBe(`${base}/channel-icons/${id}/${hash}.webp`); }); test('defaultAvatar default', () => { - expect(cdn.defaultAvatar(defaultAvatar)).toBe(`${base}/embed/avatars/${defaultAvatar}.png`); + expect(cdn.defaultAvatar(defaultAvatar)).toBe(`${base}/embed/avatars/${defaultAvatar}.webp`); }); test('discoverySplash default', () => { - expect(cdn.discoverySplash(id, hash)).toBe(`${base}/discovery-splashes/${id}/${hash}.png`); + expect(cdn.discoverySplash(id, hash)).toBe(`${base}/discovery-splashes/${id}/${hash}.webp`); }); test('emoji default', () => { - expect(cdn.emoji(id)).toBe(`${base}/emojis/${id}.png`); + expect(cdn.emoji(id)).toBe(`${base}/emojis/${id}.webp`); }); test('emoji gif', () => { @@ -53,39 +53,37 @@ test('emoji gif', () => { }); test('guildMemberAvatar default', () => { - expect(cdn.guildMemberAvatar(id, id, hash)).toBe(`${base}/guilds/${id}/users/${id}/avatars/${hash}.png`); + expect(cdn.guildMemberAvatar(id, id, hash)).toBe(`${base}/guilds/${id}/users/${id}/avatars/${hash}.webp`); }); test('guildMemberAvatar dynamic-animated', () => { - expect(cdn.guildMemberAvatar(id, id, animatedHash, { dynamic: true })).toBe( + expect(cdn.guildMemberAvatar(id, id, animatedHash)).toBe( `${base}/guilds/${id}/users/${id}/avatars/${animatedHash}.gif`, ); }); test('guildMemberAvatar dynamic-not-animated', () => { - expect(cdn.guildMemberAvatar(id, id, hash, { dynamic: true })).toBe( - `${base}/guilds/${id}/users/${id}/avatars/${hash}.png`, - ); + expect(cdn.guildMemberAvatar(id, id, hash)).toBe(`${base}/guilds/${id}/users/${id}/avatars/${hash}.webp`); }); test('icon default', () => { - expect(cdn.icon(id, hash)).toBe(`${base}/icons/${id}/${hash}.png`); + expect(cdn.icon(id, hash)).toBe(`${base}/icons/${id}/${hash}.webp`); }); test('icon dynamic-animated', () => { - expect(cdn.icon(id, animatedHash, { dynamic: true })).toBe(`${base}/icons/${id}/${animatedHash}.gif`); + expect(cdn.icon(id, animatedHash)).toBe(`${base}/icons/${id}/${animatedHash}.gif`); }); test('icon dynamic-not-animated', () => { - expect(cdn.icon(id, hash, { dynamic: true })).toBe(`${base}/icons/${id}/${hash}.png`); + expect(cdn.icon(id, hash)).toBe(`${base}/icons/${id}/${hash}.webp`); }); test('role icon default', () => { - expect(cdn.roleIcon(id, hash)).toBe(`${base}/role-icons/${id}/${hash}.png`); + expect(cdn.roleIcon(id, hash)).toBe(`${base}/role-icons/${id}/${hash}.webp`); }); test('splash default', () => { - expect(cdn.splash(id, hash)).toBe(`${base}/splashes/${id}/${hash}.png`); + expect(cdn.splash(id, hash)).toBe(`${base}/splashes/${id}/${hash}.webp`); }); test('sticker default', () => { @@ -93,11 +91,11 @@ test('sticker default', () => { }); test('stickerPackBanner default', () => { - expect(cdn.stickerPackBanner(id)).toBe(`${base}/app-assets/710982414301790216/store/${id}.png`); + expect(cdn.stickerPackBanner(id)).toBe(`${base}/app-assets/710982414301790216/store/${id}.webp`); }); test('teamIcon default', () => { - expect(cdn.teamIcon(id, hash)).toBe(`${base}/team-icons/${id}/${hash}.png`); + expect(cdn.teamIcon(id, hash)).toBe(`${base}/team-icons/${id}/${hash}.webp`); }); test('makeURL throws on invalid size', () => { @@ -107,9 +105,9 @@ test('makeURL throws on invalid size', () => { test('makeURL throws on invalid extension', () => { // @ts-expect-error: Invalid extension - expect(() => cdn.avatar(id, animatedHash, { extension: 'tif' })).toThrow(RangeError); + expect(() => cdn.avatar(id, animatedHash, { extension: 'tif', forceStatic: true })).toThrow(RangeError); }); test('makeURL valid size', () => { - expect(cdn.avatar(id, animatedHash, { size: 512 })).toBe(`${base}/avatars/${id}/${animatedHash}.png?size=512`); + expect(cdn.avatar(id, animatedHash, { size: 512 })).toBe(`${base}/avatars/${id}/${animatedHash}.gif?size=512`); }); diff --git a/packages/rest/src/lib/CDN.ts b/packages/rest/src/lib/CDN.ts index 106213f78..1760c7dbc 100644 --- a/packages/rest/src/lib/CDN.ts +++ b/packages/rest/src/lib/CDN.ts @@ -8,19 +8,48 @@ import { StickerExtension, } from './utils/constants'; +/** + * The options used for image URLs + */ export interface BaseImageURLOptions { + /** + * The extension to use for the image URL + * @default 'webp' + */ extension?: ImageExtension; + /** + * The size specified in the image URL + */ size?: ImageSize; } +/** + * The options used for image URLs with animated content + */ export interface ImageURLOptions extends BaseImageURLOptions { - dynamic?: boolean; + /** + * Whether or not to prefer the static version of an image asset. + */ + forceStatic?: boolean; } +/** + * The options to use when making a CDN URL + */ export interface MakeURLOptions { + /** + * The extension to use for the image URL + * @default 'webp' + */ extension?: string | undefined; + /** + * The size specified in the image URL + */ size?: ImageSize; - allowedExtensions?: readonly string[]; + /** + * The allowed extensions that can be used + */ + allowedExtensions?: ReadonlyArray; } /** @@ -158,7 +187,10 @@ export class CDN { * @param extension The extension of the sticker */ public sticker(stickerId: string, extension?: StickerExtension): string { - return this.makeURL(`/stickers/${stickerId}`, { allowedExtensions: ALLOWED_STICKER_EXTENSIONS, extension }); + return this.makeURL(`/stickers/${stickerId}`, { + allowedExtensions: ALLOWED_STICKER_EXTENSIONS, + extension: extension ?? 'png', // Stickers cannot have a `.webp` extension, so we default to a `.png` + }); } /** @@ -189,9 +221,9 @@ export class CDN { private dynamicMakeURL( route: string, hash: string, - { dynamic = false, ...options }: Readonly = {}, + { forceStatic = false, ...options }: Readonly = {}, ): string { - return this.makeURL(route, dynamic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options); + return this.makeURL(route, !forceStatic && hash.startsWith('a_') ? { ...options, extension: 'gif' } : options); } /** @@ -201,7 +233,7 @@ export class CDN { */ private makeURL( route: string, - { allowedExtensions = ALLOWED_EXTENSIONS, extension = 'png', size }: Readonly = {}, + { allowedExtensions = ALLOWED_EXTENSIONS, extension = 'webp', size }: Readonly = {}, ): string { extension = String(extension).toLowerCase();