Skip to content

Commit fb24946

Browse files
authored
Refactor server.js for improved emote tracking
Refactored server.js to improve structure and functionality, including updates to emote fetching and user tracking.
1 parent db09175 commit fb24946

File tree

1 file changed

+44
-66
lines changed

1 file changed

+44
-66
lines changed

server.js

Lines changed: 44 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -2,146 +2,124 @@ import express from "express";
22
import fetch from "node-fetch";
33
import tmi from "tmi.js";
44
import { WebSocketServer } from "ws";
5-
import fs from "fs";
5+
import path from "path";
66

77
const app = express();
88
const PORT = 3000;
9-
const DATA_FILE = "./data.json";
9+
const __dirname = process.cwd();
1010

11-
let allTimeData = {};
12-
if (fs.existsSync(DATA_FILE)) {
13-
try {
14-
allTimeData = JSON.parse(fs.readFileSync(DATA_FILE, "utf8"));
15-
} catch {
16-
allTimeData = {};
17-
}
18-
} else {
19-
fs.writeFileSync(DATA_FILE, "{}");
20-
}
21-
22-
const activeChannels = {}; // { channel: { emotes, users, client } }
11+
const activeChannels = {}; // { channel: { emotes:[], users:{}, emoteUsage:{} } }
2312

2413
app.use(express.static("public"));
2514

26-
// Save leaderboard data every minute
27-
setInterval(() => {
28-
fs.writeFileSync(DATA_FILE, JSON.stringify(allTimeData, null, 2));
29-
}, 60000);
30-
31-
// Fetch 7TV emotes for a channel
15+
// 🔹 Get 7TV emotes for a channel
3216
async function get7TVEmotes(channel) {
3317
try {
3418
const res = await fetch(`https://7tv.io/v3/users/twitch/${channel}`);
35-
if (!res.ok) return [];
3619
const data = await res.json();
37-
return (
38-
data.emote_set?.emotes?.map((e) => ({
39-
name: e.name,
40-
id: e.id,
41-
})) || []
42-
);
43-
} catch {
20+
return data.emote_set?.emotes?.map(e => ({
21+
name: e.name,
22+
id: e.id,
23+
url: `https://cdn.7tv.app/emote/${e.id}/4x.webp`
24+
})) || [];
25+
} catch (e) {
26+
console.log("7TV fetch failed:", e);
4427
return [];
4528
}
4629
}
4730

48-
// Get Twitch/7TV user info
31+
// 🔹 Get Twitch user info
4932
async function getTwitchUser(username) {
5033
try {
5134
const res = await fetch(`https://7tv.io/v3/users/twitch/${username}`);
5235
if (!res.ok) return null;
5336
const data = await res.json();
5437
return {
55-
id: data.id || username,
56-
avatar: data.avatar_url || null,
57-
paint: data.style?.paint || null,
38+
id: data.id,
39+
avatar: data.avatar_url || "https://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_70x70.png",
40+
paint: data.style?.paint_id || null
5841
};
5942
} catch {
6043
return null;
6144
}
6245
}
6346

64-
// Start tracking a Twitch channel
47+
// 🔹 Connect and track emotes in a channel
6548
async function startTracking(channel) {
6649
if (activeChannels[channel]) return activeChannels[channel];
67-
console.log(`🟣 Tracking started for #${channel}`);
50+
console.log(`Starting tracking for ${channel}`);
6851

6952
const emotes = await get7TVEmotes(channel);
70-
const users = allTimeData[channel] || {};
53+
const users = {};
54+
const emoteUsage = {};
7155

7256
const client = new tmi.Client({
7357
connection: { reconnect: true },
74-
channels: [channel],
58+
channels: [channel]
7559
});
7660

7761
client.connect();
7862

7963
client.on("message", async (ch, tags, msg, self) => {
8064
if (self) return;
81-
8265
const username = tags["display-name"] || tags.username;
66+
8367
if (!users[username]) {
8468
const info = await getTwitchUser(username);
8569
users[username] = {
8670
username,
8771
id: info?.id || username,
88-
avatar:
89-
info?.avatar ||
90-
"https://static-cdn.jtvnw.net/jtv_user_pictures/xarth/404_user_70x70.png",
91-
paint: info?.paint || null,
92-
count: 0,
93-
emoteUsage: {},
72+
avatar: info?.avatar,
73+
paint: info?.paint,
74+
count: 0
9475
};
9576
}
9677

9778
const words = msg.split(/\s+/);
98-
const used = emotes.filter((e) => words.includes(e.name));
79+
const used = emotes.filter(e => words.includes(e.name));
80+
9981
if (used.length > 0) {
10082
for (const e of used) {
10183
users[username].count++;
102-
users[username].emoteUsage[e.name] =
103-
(users[username].emoteUsage[e.name] || 0) + 1;
84+
emoteUsage[e.name] = (emoteUsage[e.name] || 0) + 1;
10485
}
105-
allTimeData[channel] = users;
106-
broadcast(channel, { type: "update", user: users[username] });
86+
broadcast(channel, { type: "update", user: users[username], emoteUsage });
10787
}
10888
});
10989

110-
activeChannels[channel] = { emotes, users, client };
111-
allTimeData[channel] = users;
90+
activeChannels[channel] = { emotes, users, emoteUsage, client };
11291
return activeChannels[channel];
11392
}
11493

115-
// WebSocket setup
94+
// 🔹 WebSocket setup
11695
const wss = new WebSocketServer({ noServer: true });
11796
const sockets = new Set();
11897

11998
function broadcast(channel, data) {
12099
const msg = JSON.stringify({ channel, ...data });
121-
for (const ws of sockets) {
122-
if (ws.readyState === ws.OPEN) ws.send(msg);
123-
}
100+
for (const ws of sockets) ws.send(msg);
124101
}
125102

126-
const server = app.listen(PORT, () =>
127-
console.log(`✅ Running at http://localhost:${PORT}`)
128-
);
103+
const server = app.listen(PORT, () => {
104+
console.log(`✅ Running at http://localhost:${PORT}`);
105+
});
129106

130107
server.on("upgrade", (req, socket, head) => {
131-
wss.handleUpgrade(req, socket, head, (ws) => {
108+
wss.handleUpgrade(req, socket, head, ws => {
132109
sockets.add(ws);
133110
ws.on("close", () => sockets.delete(ws));
134111
});
135112
});
136113

137-
// API routes
138-
app.get("/api/start/:channel", async (req, res) => {
114+
// 🔹 API Routes
115+
app.get("/api/channel/:channel", async (req, res) => {
139116
const channel = req.params.channel.toLowerCase();
140-
await startTracking(channel);
141-
res.json({ success: true });
117+
const tracker = await startTracking(channel);
118+
res.json({
119+
emotes: tracker.emotes,
120+
users: Object.values(tracker.users),
121+
emoteUsage: tracker.emoteUsage
122+
});
142123
});
143124

144-
app.get("/api/leaderboard/:channel", async (req, res) => {
145-
const channel = req.params.channel.toLowerCase();
146-
res.json(Object.values(allTimeData[channel] || {}));
147-
});
125+
app.use(express.static(path.join(__dirname, "public")));

0 commit comments

Comments
 (0)