Simple solution
The simplest solution for discord.js v12 I came up with:
async function getUserBannerUrl(userId) {
const user = await client.api.users(userId).get();
return user.banner ? `https://cdn.discordapp.com/banners/${userId}/${user.banner}?size=512` : null;
}
However this doesn't handle mime types well. You don't know what the mime type is unless you read the content-type header. This may break some things that require you to have a file extension in your URL. That's why I came up with more complex solution.
Complex solution
The code below is dependent on axios.
const axios = require("axios");
async function getUserBannerUrl(userId, { dynamicFormat = true, defaultFormat = "webp", size = 512 } = {}) {
// Supported image sizes, inspired by 'https://discord.js.org/#/docs/main/stable/typedef/ImageURLOptions'.
if (![16, 32, 64, 128, 256, 512, 1024, 2048, 4096].includes(size)) {
throw new Error(`The size '${size}' is not supported!`);
}
// We don't support gif as a default format,
// because requesting .gif format when the original image is not a gif,
// would result in an error 415 Unsupported Media Type.
// If you want gif support, enable dynamicFormat, .gif will be used when is it available.
if (!["webp", "png", "jpg", "jpeg"].includes(defaultFormat)) {
throw new Error(`The format '${defaultFormat}' is not supported as a default format!`);
}
// We use raw API request to get the User object from Discord API,
// since the discord.js v12's one doens't support .banner property.
const user = await client.api.users(userId).get();
if (!user.banner) return null;
const query = `?size=${size}`;
const baseUrl = `https://cdn.discordapp.com/banners/${userId}/${user.banner}`;
// If dynamic format is enabled we perform a HTTP HEAD request,
// so we can use the content-type header to determine,
// if the image is a gif or not.
if (dynamicFormat) {
const { headers } = await axios.head(baseUrl);
if (headers && headers.hasOwnProperty("content-type")) {
return baseUrl + (headers["content-type"] == "image/gif" ? ".gif" : `.${defaultFormat}`) + query;
}
}
return baseUrl + `.${defaultFormat}` + query;
}
Example usage
Implementing simple !banner command, that will show the message sender's banner.
client.on("message", async (message) => {
if (message.author.bot) return;
if (message.content == "!banner") {
const bannerUrl = await getUserBannerUrl(message.author.id, { size: 4096 });
if (bannerUrl) {
const embed = new Discord.MessageEmbed()
.setTitle(`${message.author.username}'s banner`)
.setDescription("Look at my banner, how cool is that?")
.setImage(bannerUrl);
message.channel.send(embed);
} else {
message.channel.send("You don't have money to buy Discord Nitro... How sad...");
}
}
});
