diff options
| author | ilotterytea <iltsu@alright.party> | 2025-10-31 17:14:06 +0500 |
|---|---|---|
| committer | ilotterytea <iltsu@alright.party> | 2025-10-31 17:14:06 +0500 |
| commit | aed413b1bed8dc2883a94262e4c6fa64e7e986de (patch) | |
| tree | 59e7a4d10a7253b69e194469544990fca726c2db | |
| parent | ddc4730d6ba1629b10babc4ece7e6b5995d97cea (diff) | |
feat: connect to twitch chat
| -rw-r--r-- | index.html | 14 | ||||
| -rw-r--r-- | scripts/chat.js | 98 |
2 files changed, 111 insertions, 1 deletions
@@ -4,6 +4,18 @@ <title>webberino</title> </head> <body> - <h1>xd</h1> + <div class="tabs" id="main-window-tabs"></div> + <div class="messages" id="window-messages"> + <noscript>JavaScript is required.</noscript> + </div> + <div class="input-field" id="main-window-input-field"></div> </body> + <script src="/scripts/chat.js"></script> + <script> + window.onload = () => { + const client = new TwitchIRCClient("wss://irc-ws.chat.twitch.tv", "justinfan65432", "12345"); + client.connect(); + client.join("forsen"); + }; + </script> </html>
\ No newline at end of file diff --git a/scripts/chat.js b/scripts/chat.js new file mode 100644 index 0000000..b78f946 --- /dev/null +++ b/scripts/chat.js @@ -0,0 +1,98 @@ +function displayMessage(data) { + const messages = document.getElementById("window-messages"); + + const message = document.createElement("p"); + message.classList.add("message"); + + if ("nick" in data && data.nick.length > 0) { + const nickElement = document.createElement("span"); + nickElement.classList.add("nick"); + nickElement.textContent = `${data.nick}: `; + + if ("color" in data.tags) { + nickElement.style.color = data.tags["color"]; + } + + message.append(nickElement); + } + + const messageContent = document.createElement("span"); + messageContent.classList.add("content"); + messageContent.textContent = data.params[1]; + message.append(messageContent); + + messages.append(message); +} + +function displaySystemMessage(channelName, message, nick = "System") { + displayMessage({ + "nick": nick, + "prefix": nick, + "command": "PRIVMSG", + "params": [channelName, message], + "tags": {} + }); +} + +class TwitchIRCClient { + constructor (host, nick, pass) { + this.joinedChannels = []; + this.socket = null; + this.host = host; + this.nick = nick; + this.pass = pass; + } + + connect() { + this.socket = new WebSocket(this.host); + + this.socket.addEventListener("open", () => { + this.socket.send(`NICK ${this.nick}`); + this.socket.send(`PASS ${this.pass}`); + this.socket.send(`CAP REQ :twitch.tv/tags twitch.tv/membership`); + }); + + this.socket.addEventListener("message", (e) => { + const lines = e.data.split("\r\n"); + for (const line of lines) { + if (line.trim().length == 0) { + continue; + } + if (line.includes("001")) { + for (const c of this.joinedChannels) { + this.join(c); + } + displaySystemMessage("*", "Connected!"); + } + displaySystemMessage("forsen", line, "Message"); + } + }); + + this.socket.addEventListener("error", (e) => { + console.error(e); + }); + + this.socket.addEventListener("close", (e) => { + for (const c of this.joinedChannels) { + displaySystemMessage(c, `Disconnected! Reason: ${e.reason}`); + displaySystemMessage(c, "Reconnecting in 10 seconds..."); + } + + setTimeout(() => this.connect(), 10000); + }); + } + + say(channelName, message) { + this.socket.send(`PRIVMSG #${channelName} :${message}`); + } + + join(channelName) { + if (this.socket != null && this.socket.readyState == this.socket.OPEN) { + this.socket.send(`JOIN #${channelName}`); + } + + if (!this.joinedChannels.includes(channelName)) { + this.joinedChannels.push(channelName); + } + } +}
\ No newline at end of file |
