summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorilotterytea <iltsu@alright.party>2025-10-31 17:14:06 +0500
committerilotterytea <iltsu@alright.party>2025-10-31 17:14:06 +0500
commitaed413b1bed8dc2883a94262e4c6fa64e7e986de (patch)
tree59e7a4d10a7253b69e194469544990fca726c2db
parentddc4730d6ba1629b10babc4ece7e6b5995d97cea (diff)
feat: connect to twitch chat
-rw-r--r--index.html14
-rw-r--r--scripts/chat.js98
2 files changed, 111 insertions, 1 deletions
diff --git a/index.html b/index.html
index c484ff9..de2f7a0 100644
--- a/index.html
+++ b/index.html
@@ -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