Skip to content

Commit a3ee62b

Browse files
authored
Update index.html
1 parent e010889 commit a3ee62b

File tree

1 file changed

+84
-171
lines changed

1 file changed

+84
-171
lines changed

index.html

Lines changed: 84 additions & 171 deletions
Original file line numberDiff line numberDiff line change
@@ -4,156 +4,15 @@
44
<meta charset="UTF-8" />
55
<title>7TV Live Emote Tracker</title>
66
<style>
7-
* {
8-
box-sizing: border-box;
9-
}
10-
body {
11-
margin: 0;
12-
font-family: 'Inter', sans-serif;
13-
background: #0a0013;
14-
color: #fff;
15-
text-align: center;
16-
min-height: 100vh;
17-
background-image: url("peepo.png");
18-
background-size: cover;
19-
background-position: center;
20-
background-attachment: fixed;
21-
background-repeat: no-repeat;
22-
overflow-x: hidden;
23-
}
24-
25-
body::before {
26-
content: "";
27-
position: fixed;
28-
inset: 0;
29-
background: radial-gradient(circle at top left, rgba(90, 0, 255, 0.4), transparent),
30-
radial-gradient(circle at bottom right, rgba(180, 0, 255, 0.25), transparent),
31-
rgba(0, 0, 0, 0.85);
32-
backdrop-filter: blur(12px);
33-
z-index: -1;
34-
}
35-
36-
h1 {
37-
margin-top: 1.2rem;
38-
font-size: 2rem;
39-
color: #c8a9ff;
40-
text-shadow: 0 0 10px #a76eff, 0 0 25px #6b2cff;
41-
animation: glowPulse 2s infinite alternate;
42-
}
43-
44-
@keyframes glowPulse {
45-
from { text-shadow: 0 0 8px #9b59ff, 0 0 16px #823bff; }
46-
to { text-shadow: 0 0 18px #bb8cff, 0 0 32px #b57bff; }
47-
}
48-
49-
input, button {
50-
padding: 0.6rem 1rem;
51-
border: 2px solid #9146FF;
52-
border-radius: 10px;
53-
background: #161024;
54-
color: white;
55-
margin: 0.5rem;
56-
font-size: 1rem;
57-
transition: 0.3s;
58-
box-shadow: 0 0 10px rgba(145, 70, 255, 0.3);
59-
}
60-
61-
input:focus {
62-
border-color: #b68cff;
63-
outline: none;
64-
box-shadow: 0 0 12px #b68cff;
65-
}
66-
67-
button {
68-
background: linear-gradient(90deg, #9146FF, #b88cff);
69-
cursor: pointer;
70-
font-weight: bold;
71-
box-shadow: 0 0 12px #9146ff7a;
72-
}
73-
74-
button:hover {
75-
box-shadow: 0 0 18px #b88cff;
76-
transform: scale(1.03);
77-
}
78-
79-
#title {
80-
margin-top: 0.8rem;
81-
font-size: 1.2rem;
82-
color: #c7b6ff;
83-
text-shadow: 0 0 8px #8f6cff;
84-
}
85-
86-
#tables {
87-
display: flex;
88-
justify-content: space-around;
89-
flex-wrap: wrap;
90-
margin-top: 2rem;
91-
}
92-
93-
.table-container {
94-
width: 45%;
95-
min-width: 320px;
96-
background: rgba(10, 0, 25, 0.6);
97-
border: 2px solid rgba(130, 60, 255, 0.4);
98-
border-radius: 15px;
99-
box-shadow: 0 0 20px rgba(145, 70, 255, 0.15);
100-
padding: 1rem;
101-
transition: 0.3s;
102-
}
103-
104-
.table-container:hover {
105-
box-shadow: 0 0 30px rgba(160, 90, 255, 0.3);
106-
}
107-
108-
h2 {
109-
color: #d2b6ff;
110-
text-shadow: 0 0 8px #a66eff;
111-
font-weight: 600;
112-
}
113-
114-
table {
115-
width: 100%;
116-
border-collapse: collapse;
117-
margin-top: 1rem;
118-
background: rgba(25, 10, 40, 0.6);
119-
border-radius: 10px;
120-
overflow: hidden;
121-
}
122-
123-
th, td {
124-
padding: 10px 16px;
125-
border-bottom: 1px solid rgba(90, 50, 160, 0.3);
126-
}
127-
128-
th {
129-
background: rgba(90, 40, 160, 0.3);
130-
color: #c6a3ff;
131-
text-transform: uppercase;
132-
font-size: 0.85rem;
133-
letter-spacing: 1px;
134-
}
135-
136-
td {
137-
color: #fff;
138-
font-size: 1rem;
139-
}
140-
141-
tr:nth-child(even) {
142-
background: rgba(50, 30, 90, 0.4);
143-
}
144-
145-
tr:hover {
146-
background: rgba(100, 50, 200, 0.4);
147-
transition: 0.2s;
148-
}
7+
/* (Keep your CSS here, unchanged for brevity) */
1498
</style>
1509
</head>
15110
<body>
15211
<h1>💫 7TV Live Tracker</h1>
15312

15413
<div>
15514
<input id="channelInput" placeholder="Enter Twitch channel..." />
156-
<button onclick="loadChannel()">Track Channel</button>
15+
<button onclick="connectStreamElements()">Track Channel</button>
15716
</div>
15817
<div id="title"></div>
15918

@@ -176,45 +35,99 @@ <h2>🎭 Emote Leaderboard</h2>
17635
</div>
17736

17837
<script>
179-
const ws = new WebSocket(`ws://${location.host}`);
180-
let channel = null;
181-
let users = {};
38+
let seSocket = null;
39+
let userUsage = {};
18240
let emoteUsage = {};
41+
let channel = null;
18342

184-
ws.onmessage = (e) => {
185-
const data = JSON.parse(e.data);
186-
if (data.channel === channel && data.type === "update") {
187-
users[data.user.id] = data.user;
188-
emoteUsage = data.emoteUsage;
189-
render();
190-
}
191-
};
192-
193-
async function loadChannel() {
43+
function connectStreamElements() {
19444
channel = document.getElementById("channelInput").value.trim().toLowerCase();
195-
if (!channel) return;
196-
const res = await fetch(`/api/channel/${channel}`);
197-
const data = await res.json();
198-
users = {};
199-
data.users.forEach((u) => (users[u.id] = u));
200-
emoteUsage = data.emoteUsage;
45+
if (!channel) return alert("Enter a Twitch channel name");
46+
20147
document.getElementById("title").innerText = `Tracking: ${channel}`;
202-
render();
48+
userUsage = {};
49+
emoteUsage = {};
50+
51+
if (seSocket) seSocket.close();
52+
53+
seSocket = new WebSocket("wss://realtime.streamelements.com/socket");
54+
55+
seSocket.onopen = () => {
56+
console.log("✅ Connected to StreamElements API");
57+
};
58+
59+
seSocket.onmessage = (event) => {
60+
const data = JSON.parse(event.data);
61+
62+
if (data.type === "welcome") {
63+
console.log("👋 Welcome:", data.payload.sessionId);
64+
65+
// Authenticate using public channel (no token needed for chat)
66+
seSocket.send(
67+
JSON.stringify({
68+
type: "authenticate",
69+
payload: {
70+
method: "jwt",
71+
token: null
72+
}
73+
})
74+
);
75+
76+
// Subscribe to chat for the specified channel
77+
// You’ll need the channel’s StreamElements channel ID
78+
fetch(`https://api.streamelements.com/kappa/v2/channels/${channel}`)
79+
.then((r) => r.json())
80+
.then((ch) => {
81+
console.log("🎯 Subscribing to channel:", ch._id, ch.username);
82+
seSocket.send(
83+
JSON.stringify({
84+
type: "listen",
85+
event: `message:${ch._id}`,
86+
})
87+
);
88+
})
89+
.catch((err) => {
90+
console.error("❌ Failed to get channel:", err);
91+
});
92+
}
93+
94+
if (data.type === "ping") {
95+
seSocket.send(JSON.stringify({ type: "pong" }));
96+
}
97+
98+
if (data.type === "event" && data.event?.type === "message") {
99+
const msg = data.event.data;
100+
const username = msg.nick || "Unknown";
101+
const emotes = msg.emotes || [];
102+
103+
userUsage[username] = (userUsage[username] || 0) + 1;
104+
105+
emotes.forEach((e) => {
106+
const name = e.text || e.name || "unknown";
107+
emoteUsage[name] = (emoteUsage[name] || 0) + 1;
108+
});
109+
110+
render();
111+
}
112+
};
113+
114+
seSocket.onerror = (err) => console.error("WebSocket error:", err);
115+
seSocket.onclose = () => console.log("⚠️ Disconnected from StreamElements");
203116
}
204117

205118
function render() {
206-
const sortedUsers = Object.values(users).sort((a, b) => b.count - a.count);
207-
const sortedEmotes = Object.entries(emoteUsage)
119+
const sortedUsers = Object.entries(userUsage)
208120
.sort((a, b) => b[1] - a[1])
209-
.map(([name, count]) => ({ name, count }));
210-
211-
document.getElementById("userboard").innerHTML = sortedUsers
212-
.map((u, i) => `<tr><td>${i + 1}</td><td>${u.username}</td><td>${u.count}</td></tr>`)
121+
.map(([username, count], i) => `<tr><td>${i + 1}</td><td>${username}</td><td>${count}</td></tr>`)
213122
.join("");
214123

215-
document.getElementById("emoteboard").innerHTML = sortedEmotes
216-
.map((e, i) => `<tr><td>${i + 1}</td><td>${e.name}</td><td>${e.count}</td></tr>`)
124+
const sortedEmotes = Object.entries(emoteUsage)
125+
.sort((a, b) => b[1] - a[1])
126+
.map(([emote, count], i) => `<tr><td>${i + 1}</td><td>${emote}</td><td>${count}</td></tr>`)
217127
.join("");
128+
129+
document.getElementById("userboard").innerHTML = sortedUsers;
130+
document.getElementById("emoteboard").innerHTML = sortedEmotes;
218131
}
219132
</script>
220133
</body>

0 commit comments

Comments
 (0)