fix: discord avatars not loading (@fehmer)

This commit is contained in:
Christian Fehmer 2025-09-26 12:09:13 +02:00
parent a15d84e0ce
commit 7a2e9711f4
No known key found for this signature in database
GPG key ID: FE53784A69964062
4 changed files with 48 additions and 61 deletions

View file

@ -350,14 +350,20 @@ key {
line-height: 1em;
font-size: var(--size);
border-radius: 100%;
background-position: center center;
background-size: contain;
background-repeat: no-repeat;
grid-column: 1/2;
grid-row: 1/2;
place-self: center center;
display: grid;
place-content: center center;
overflow: hidden;
display: inline-block;
z-index: 1; //place above the loading spinner
img {
width: 100%;
height: 100%;
object-fit: cover;
display: block;
}
}
.loading {

View file

@ -51,6 +51,7 @@ import * as Cookies from "./cookies";
import "./elements/psa";
import "./utils/url-handler";
import "./modals/last-signed-out-result";
import { addToGlobal } from "./utils/global";
// Lock Math.random
Object.defineProperty(Math, "random", {
@ -71,13 +72,6 @@ Object.defineProperty(window, "Math", {
enumerable: true,
});
function addToGlobal(items: Record<string, unknown>): void {
for (const [name, item] of Object.entries(items)) {
//@ts-expect-error dev
window[name] = item;
}
}
void loadFromLocalStorage();
void VersionButton.update();
Focus.set(true, true);

View file

@ -1,29 +1,40 @@
const cachedAvatarUrlByAvatarId: Map<string, string | null> = new Map();
import { addToGlobal } from "./global";
type Options = { size?: number; userIcon?: string };
function buildElement(
url: string | null,
options?: { loading?: boolean } & Options
): HTMLElement {
const knownBadUrls = new Set();
function buildElement(url: string | null, options?: Options): HTMLElement {
const avatar = document.createElement("div");
avatar.classList.add("avatar");
if (url === null) {
if (options?.loading) {
avatar.innerHTML = `<div class="loading"><i class="fas fa-circle-notch fa-spin"><i></div>`;
} else {
avatar.innerHTML = `<div class="userIcon"><i class="${
options?.userIcon ?? "fas fa-user-circle"
}"><i></div>`;
}
if (url === null || knownBadUrls.has(url)) {
avatar.innerHTML = `<div class="userIcon"><i class="${
options?.userIcon ?? "fas fa-user-circle"
}"></i></div>`;
} else {
avatar.innerHTML = `<div class="discordImage" style="background-image:url(${url}?size=${
options?.size ?? 32
})"></div>`;
avatar.innerHTML = `
<div class="loading"><i class="fas fa-circle-notch fa-spin"></i></div>
<div class="discordImage">
<img src="${url}?size=${options?.size ?? 32})"
onload="onAvatarLoaded(this)" onerror="onAvatarError(this)"
></img>
</div>`;
}
return avatar;
}
addToGlobal({
onAvatarLoaded: (element: HTMLImageElement): void => {
element.closest(".avatar")?.querySelector(".loading")?.remove();
},
onAvatarError: (element: HTMLImageElement): void => {
knownBadUrls.add(element.src.split("?")[0]);
element.closest(".avatar")?.replaceWith(buildElement(null));
},
});
export function getAvatarElement(
{
discordId,
@ -43,40 +54,10 @@ export function getAvatarElement(
return buildElement(null, options);
}
const cachedUrl = cachedAvatarUrlByAvatarId.get(discordAvatar);
const element = buildElement(
`https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png`,
options
);
if (cachedUrl !== undefined) {
return buildElement(cachedUrl, options);
} else {
const element = buildElement(null, { loading: true });
void getDiscordAvatarUrl({ discordId, discordAvatar }).then((url) => {
cachedAvatarUrlByAvatarId.set(discordAvatar, url);
element.replaceWith(buildElement(url, options));
});
return element;
}
}
async function getDiscordAvatarUrl({
discordId,
discordAvatar,
}: {
discordId: string;
discordAvatar: string;
}): Promise<string | null> {
// An invalid request to this URL will return a 404.
try {
const avatarUrl = `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png`;
const response = await fetch(avatarUrl, { method: "HEAD" });
if (!response.ok) {
return null;
}
return avatarUrl;
} catch (error) {}
return null;
return element;
}

View file

@ -0,0 +1,6 @@
export function addToGlobal(items: Record<string, unknown>): void {
for (const [name, item] of Object.entries(items)) {
//@ts-expect-error dev
window[name] = item;
}
}