Skip to content

Commit 5deba04

Browse files
Rename duplicate emotes with a ~N number suffix (#597)
* Rename duplicate emotes with a ~N number suffix * Merge exact duplicates * Fix dupe check
1 parent 8029e95 commit 5deba04

File tree

1 file changed

+39
-8
lines changed

1 file changed

+39
-8
lines changed

src/plugins/emotes.js

Lines changed: 39 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,33 @@ const schema = JSON.parse(
2929
* @typedef {{ name: string, url: URL }} Emote
3030
*/
3131

32+
/**
33+
* A Map of emote names to URLs.
34+
*
35+
* @augments {Map<string, URL>}
36+
*/
37+
class EmoteMap extends Map {
38+
/**
39+
* Add an emote to the map. If an emote with the same name already exists,
40+
* this tries to add a numeric suffix to distinguish them.
41+
*
42+
* @param {Emote} emote
43+
*/
44+
insert(emote) {
45+
const prevUrl = this.get(emote.name);
46+
if (prevUrl && prevUrl.href !== emote.url.href) {
47+
for (let i = 1; i < 20; i += 1) {
48+
if (!this.has(`${emote.name}~${i}`)) {
49+
this.set(`${emote.name}~${i}`, emote.url);
50+
break;
51+
}
52+
}
53+
} else {
54+
this.set(emote.name, emote.url);
55+
}
56+
}
57+
}
58+
3259
/**
3360
* @template {object} T
3461
* @param {URL|string} url
@@ -220,8 +247,7 @@ class Emotes {
220247

221248
#logger;
222249

223-
/** @type {Record<string, URL>} */
224-
#emotes = Object.create(null);
250+
#emotes = new EmoteMap();
225251

226252
#ready = Promise.resolve();
227253

@@ -244,19 +270,25 @@ class Emotes {
244270
this.#ready = this.#reloadEmotes();
245271
}
246272

273+
/** Get all known emotes as an array. */
247274
async getEmotes() {
248275
await this.#ready;
249276

250-
return Object.entries(this.#emotes).map(([name, url]) => ({ name, url: url.toString() }));
277+
const emotes = [];
278+
for (const [name, url] of this.#emotes) {
279+
emotes.push({ name, url: url.toString() });
280+
}
281+
282+
return emotes;
251283
}
252284

253285
/**
254286
* @param {TwitchSettings} options
255-
* @returns {Promise<Record<string, URL>>}
287+
* @returns {Promise<EmoteMap>}
256288
*/
257289
async #loadTTVEmotes(options) {
258290
if (!options.clientId || !options.clientSecret) {
259-
return {};
291+
return new EmoteMap();
260292
}
261293

262294
const client = new ApiClient({
@@ -292,14 +324,13 @@ class Emotes {
292324
promises.push(getSevenTVEmotes(channels));
293325
}
294326

295-
/** @type {Record<string, URL>} */
296-
const emotes = {};
327+
const emotes = new EmoteMap();
297328

298329
const results = await Promise.allSettled(promises);
299330
for (const result of results) {
300331
if (result.status === 'fulfilled') {
301332
for (const emote of result.value) {
302-
emotes[emote.name] = emote.url;
333+
emotes.insert(emote);
303334
}
304335
} else {
305336
this.#logger.warn(result.reason);

0 commit comments

Comments
 (0)