Skip to content

Commit d9d375d

Browse files
fehmerMiodec
andauthored
fix: discord avatars not loading (@fehmer) (monkeytypegame#6999)
fixes monkeytypegame#6998 Seems it was fixed by discord in the meantime. Still I think this is a better approach because it only takes one rest call to the discord cdn instead of two for each avatar. --------- Co-authored-by: Miodec <[email protected]>
1 parent 0152521 commit d9d375d

File tree

4 files changed

+54
-63
lines changed

4 files changed

+54
-63
lines changed

frontend/src/styles/core.scss

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,14 +350,20 @@ key {
350350
line-height: 1em;
351351
font-size: var(--size);
352352
border-radius: 100%;
353-
background-position: center center;
354-
background-size: contain;
355-
background-repeat: no-repeat;
356353
grid-column: 1/2;
357354
grid-row: 1/2;
358355
place-self: center center;
359356
display: grid;
360357
place-content: center center;
358+
overflow: hidden;
359+
display: inline-block;
360+
z-index: 1; //place above the loading spinner
361+
img {
362+
width: 100%;
363+
height: 100%;
364+
object-fit: cover;
365+
display: block;
366+
}
361367
}
362368

363369
.loading {

frontend/src/ts/index.ts

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ import "./states/connection";
4242
import "./test/tts";
4343
import "./elements/fps-counter";
4444
import "./controllers/profile-search-controller";
45-
import { isDevEnvironment } from "./utils/misc";
45+
import { isDevEnvironment, addToGlobal } from "./utils/misc";
4646
import * as VersionButton from "./elements/version-button";
4747
import * as Focus from "./test/focus";
4848
import { getDevOptionsModal } from "./utils/async-modules";
@@ -71,13 +71,6 @@ Object.defineProperty(window, "Math", {
7171
enumerable: true,
7272
});
7373

74-
function addToGlobal(items: Record<string, unknown>): void {
75-
for (const [name, item] of Object.entries(items)) {
76-
//@ts-expect-error dev
77-
window[name] = item;
78-
}
79-
}
80-
8174
void loadFromLocalStorage();
8275
void VersionButton.update();
8376
Focus.set(true, true);
Lines changed: 37 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,41 @@
1-
const cachedAvatarUrlByAvatarId: Map<string, string | null> = new Map();
2-
31
type Options = { size?: number; userIcon?: string };
42

5-
function buildElement(
6-
url: string | null,
7-
options?: { loading?: boolean } & Options
8-
): HTMLElement {
3+
const knownBadUrls = new Set();
4+
5+
function buildElement(url: string | null, options?: Options): HTMLElement {
96
const avatar = document.createElement("div");
107
avatar.classList.add("avatar");
11-
if (url === null) {
12-
if (options?.loading) {
13-
avatar.innerHTML = `<div class="loading"><i class="fas fa-circle-notch fa-spin"><i></div>`;
14-
} else {
15-
avatar.innerHTML = `<div class="userIcon"><i class="${
16-
options?.userIcon ?? "fas fa-user-circle"
17-
}"><i></div>`;
18-
}
8+
9+
if (url === null || knownBadUrls.has(url)) {
10+
avatar.innerHTML = `<div class="userIcon"><i class="${
11+
options?.userIcon ?? "fas fa-user-circle"
12+
}"></i></div>`;
1913
} else {
20-
avatar.innerHTML = `<div class="discordImage" style="background-image:url(${url}?size=${
21-
options?.size ?? 32
22-
})"></div>`;
14+
const loading = document.createElement("div");
15+
loading.className = "loading";
16+
loading.innerHTML = '<i class="fas fa-circle-notch fa-spin"></i>';
17+
18+
const imageContainer = document.createElement("div");
19+
imageContainer.className = "discordImage";
20+
21+
const img = document.createElement("img");
22+
img.src = `${url}?size=${options?.size ?? 32}`;
23+
24+
// Add event listeners directly to the img element
25+
img.addEventListener("load", async () => {
26+
loading.remove();
27+
});
28+
29+
img.addEventListener("error", () => {
30+
knownBadUrls.add(url);
31+
avatar.replaceWith(buildElement(null, options));
32+
});
33+
34+
imageContainer.appendChild(img);
35+
avatar.appendChild(loading);
36+
avatar.appendChild(imageContainer);
2337
}
38+
2439
return avatar;
2540
}
2641

@@ -43,40 +58,10 @@ export function getAvatarElement(
4358
return buildElement(null, options);
4459
}
4560

46-
const cachedUrl = cachedAvatarUrlByAvatarId.get(discordAvatar);
47-
48-
if (cachedUrl !== undefined) {
49-
return buildElement(cachedUrl, options);
50-
} else {
51-
const element = buildElement(null, { loading: true });
52-
53-
void getDiscordAvatarUrl({ discordId, discordAvatar }).then((url) => {
54-
cachedAvatarUrlByAvatarId.set(discordAvatar, url);
55-
element.replaceWith(buildElement(url, options));
56-
});
57-
58-
return element;
59-
}
60-
}
61-
62-
async function getDiscordAvatarUrl({
63-
discordId,
64-
discordAvatar,
65-
}: {
66-
discordId: string;
67-
discordAvatar: string;
68-
}): Promise<string | null> {
69-
// An invalid request to this URL will return a 404.
70-
try {
71-
const avatarUrl = `https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png`;
72-
73-
const response = await fetch(avatarUrl, { method: "HEAD" });
74-
if (!response.ok) {
75-
return null;
76-
}
77-
78-
return avatarUrl;
79-
} catch (error) {}
61+
const element = buildElement(
62+
`https://cdn.discordapp.com/avatars/${discordId}/${discordAvatar}.png`,
63+
options
64+
);
8065

81-
return null;
66+
return element;
8267
}

frontend/src/ts/utils/misc.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -761,4 +761,11 @@ export function scrollToCenterOrTop(el: HTMLElement | null): void {
761761
});
762762
}
763763

764+
export function addToGlobal(items: Record<string, unknown>): void {
765+
for (const [name, item] of Object.entries(items)) {
766+
//@ts-expect-error dev
767+
window[name] = item;
768+
}
769+
}
770+
764771
// DO NOT ALTER GLOBAL OBJECTSONSTRUCTOR, IT WILL BREAK RESULT HASHES

0 commit comments

Comments
 (0)