This repository has been archived by the owner on Nov 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
12 changed files
with
4,655 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
{ | ||
"name": "kick-chatbot", | ||
"version": "1.0.0", | ||
"description": "Example of chat bot on kick.com", | ||
"main": "dist/index.js", | ||
"scripts": { | ||
"test": "echo \"Error: no test specified\" && exit 1", | ||
"start": "node dist/index.js", | ||
"start:dev": "nodemon src/index.ts", | ||
"prd": "node dist/index.js", | ||
"build": "tsc -p . --noEmit false" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/BOT-K4CP3R/kick-chatbot.git" | ||
}, | ||
"keywords": [ | ||
"kick.com", | ||
"chatbot" | ||
], | ||
"author": "botk4cp3r", | ||
"license": "MIT", | ||
"bugs": { | ||
"url": "https://github.com/BOT-K4CP3R/kick-chatbot/issues" | ||
}, | ||
"homepage": "https://github.com/BOT-K4CP3R/kick-chatbot#readme", | ||
"dependencies": { | ||
"axios": "^1.4.0", | ||
"cheerio": "1.0.0-rc.12", | ||
"puppeteer": "^21.5.0", | ||
"puppeteer-extra": "^3.3.6", | ||
"puppeteer-extra-plugin-stealth": "^2.11.2", | ||
"uuid": "^9.0.0", | ||
"ws": "^8.12.1" | ||
}, | ||
"devDependencies": { | ||
"@ianvs/prettier-plugin-sort-imports": "^4.0.2", | ||
"@types/eslint": "^8.40.2", | ||
"@types/node": "^18.14.6", | ||
"@types/prettier": "^2.7.3", | ||
"@types/uuid": "^9.0.1", | ||
"@types/ws": "^8.5.4", | ||
"@typescript-eslint/eslint-plugin": "^5.59.6", | ||
"@typescript-eslint/parser": "^5.59.6", | ||
"dotenv": "^16.0.3", | ||
"eslint": "^8.43.0", | ||
"nodemon": "^3.0.1", | ||
"prettier": "^2.8.8", | ||
"ts-node": "^10.9.1", | ||
"typescript": "^4.9.5" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
import { sendMessage } from "../handlers/sendMessage"; | ||
|
||
export const execute = (username: string, channelId: number) => { | ||
sendMessage(channelId, `@${username}, this is test command!`); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
interface Config { | ||
token: string; | ||
cookies: string; | ||
} | ||
|
||
const config: Config = { | ||
token : '', | ||
cookies: '' | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
import WebSocket from "ws"; | ||
import fs from "fs"; | ||
import path from "path"; | ||
|
||
import { MessageData, MessageEvent } from "@/types/events"; | ||
|
||
import { runtimeChannelData } from "../utils/index"; | ||
|
||
let responseEvents: { [channelId: string]: number } = {}; | ||
|
||
const messageParser = (message: string) => { | ||
const messageEventJSON: MessageEvent = JSON.parse(message); | ||
if (messageEventJSON.event === "App\\Events\\ChatMessageEvent") { | ||
const data: MessageData = JSON.parse(messageEventJSON.data); | ||
const message = data.content; | ||
const channelId = data.chatroom_id; | ||
const username = data.sender.username; | ||
const emoteRegex = /\[emote:\d+:[^\]]+\]/g; | ||
const channelName = runtimeChannelData.get(channelId); | ||
|
||
try { | ||
if (message.match(emoteRegex)) { | ||
const processedMsg = message.replace(emoteRegex, (match: any) => { | ||
const parts = match.substring(7, match.length - 1).split(":"); | ||
return parts[1]; | ||
}); | ||
console.log(`${channelName} | ${username}: ${processedMsg}`); | ||
} else { | ||
console.log(`${channelName} | ${username}: ${message}`); | ||
} | ||
} catch (error) { | ||
console.log("Message filter error:", error); | ||
} | ||
} | ||
}; | ||
|
||
const handleCommand = (command: string, user: string, channelId: number) => { | ||
const commandFilePath = path.resolve(__dirname, `../commands/${command}.ts`); | ||
if (fs.existsSync(commandFilePath)) { | ||
const commandHandler = require(commandFilePath); | ||
commandHandler.execute(user, channelId); | ||
} else { | ||
console.log(`Command '${command}' not found.`); | ||
} | ||
}; | ||
|
||
export const onMessage = (messageEvent: WebSocket.Data, socket: any) => { | ||
const message = messageEvent.toString(); | ||
messageParser(message); | ||
|
||
const messageEventJSON: MessageEvent = JSON.parse(message); | ||
const data: MessageData = JSON.parse(messageEventJSON.data); | ||
const channelId = data.chatroom_id; | ||
const user = data.sender; | ||
const username = user ? user.username : "Brak nazwy użytkownika"; | ||
|
||
try { | ||
const messageData = JSON.parse(message); | ||
|
||
if (messageData && typeof messageData.data === 'string') { | ||
const eventData = JSON.parse(messageData.data); | ||
|
||
if (eventData && eventData.content && typeof eventData.content === 'string') { | ||
const messageContent = eventData.content; | ||
|
||
if (messageContent.startsWith("!")) { | ||
const [command, ...args] = messageContent.slice(1).split(" "); | ||
|
||
handleCommand(command, username, channelId); | ||
} | ||
} | ||
} | ||
} catch (error) { | ||
console.log("Error parsing message data:", error); | ||
} | ||
|
||
eventCalculation(message); | ||
}; | ||
|
||
|
||
function eventCalculation(message: string) { | ||
const messageEventJSON: MessageEvent = JSON.parse(message); | ||
if (messageEventJSON.event === "App\\Events\\ChatMessageEvent") { | ||
const channelId = messageEventJSON.channel; | ||
responseEvents[channelId] = (responseEvents[channelId] || 0) + 1; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
import axios from 'axios'; | ||
import config from '../config'; | ||
|
||
export const sendMessage = async (channelId: number, messageContent: string) => { | ||
axios.post(`https://kick.com/api/v2/messages/send/${channelId}`, | ||
{ | ||
content: messageContent, | ||
type: "message" | ||
}, | ||
{ | ||
headers: { | ||
"accept": "application/json, text/plain, */*", | ||
"authorization": `Bearer ${config.token}`, | ||
"content-type": "application/json", | ||
"x-xsrf-token": config.token, | ||
"cookie": config.cookies, | ||
"Referer": "https://kick.com/botk4cp3r" | ||
} | ||
}); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
import { URLSearchParams } from "url"; | ||
import { v4 as uuidv4 } from "uuid"; | ||
import WebSocket from "ws"; | ||
import config from './config' | ||
|
||
import { onMessage } from "./handlers/onMessage"; | ||
import { getChatroomId, runtimeChannelData } from "./utils"; | ||
|
||
const baseUrl = "wss://ws-us2.pusher.com/app/eb1d5f283081a78b932c"; | ||
const urlParams = new URLSearchParams({ | ||
protocol: "7", | ||
client: "js", | ||
version: "7.4.0", | ||
flash: "false", | ||
}); | ||
const url = `${baseUrl}?${urlParams.toString()}`; | ||
|
||
const maxChannelsPerSocket = 10; | ||
let activeSockets: WebSocket[] = []; | ||
|
||
const connectToChannels = async (socket: WebSocket, channels: any[]) => { | ||
channels.forEach(async (channel) => { | ||
const connect = JSON.stringify({ | ||
event: "pusher:subscribe", | ||
data: { auth: config.token, channel: `chatrooms.${channel}.v2` }, | ||
}); | ||
await socket.send(connect); | ||
const channelName = runtimeChannelData.get(channel); | ||
console.log(`connected to #${channelName}`); | ||
}); | ||
}; | ||
|
||
const createNewSocket = async (channels: number[]) => { | ||
const socket = new WebSocket(url); | ||
const id = uuidv4(); | ||
socket.on("open", () => { | ||
console.log(`Connected to socket server ${id}`); | ||
activeSockets.push(socket); | ||
connectToChannels(socket, channels); | ||
}); | ||
socket.on("message", (data: WebSocket.Data) => { | ||
const messageEvent = data.toString(); | ||
onMessage(messageEvent, socket); | ||
}); | ||
socket.on("close", () => { | ||
console.log("Disconnected from server"); | ||
activeSockets = activeSockets.filter((s) => s !== socket); | ||
}); | ||
}; | ||
|
||
const countConnectedChannels = (socket: WebSocket): number => { | ||
let count = 0; | ||
socket.listeners("message").forEach((listener) => { | ||
const connectEvent = JSON.parse(listener.toString()); | ||
if (connectEvent && connectEvent.event === "pusher:subscribe") { | ||
count++; | ||
} | ||
}); | ||
return count; | ||
}; | ||
|
||
const connectToDynamicChannels = async (channels: number[]) => { | ||
console.log(`Connecting to ${channels.length} channels...`); | ||
activeSockets.forEach((socket) => { | ||
const connectedChannelCount = countConnectedChannels(socket); | ||
console.log( | ||
`Socket ${socket.url} is connected to ${connectedChannelCount} channels` | ||
); | ||
}); | ||
let connectedChannelCount = 0; | ||
activeSockets.forEach((socket) => { | ||
if (connectedChannelCount < maxChannelsPerSocket) { | ||
const channelsToConnect = channels.slice( | ||
connectedChannelCount, | ||
maxChannelsPerSocket - connectedChannelCount | ||
); | ||
connectToChannels(socket, channelsToConnect); | ||
connectedChannelCount += channelsToConnect.length; | ||
} | ||
}); | ||
while (connectedChannelCount < channels.length) { | ||
const channelsToConnect = channels.slice( | ||
connectedChannelCount, | ||
connectedChannelCount + maxChannelsPerSocket | ||
); | ||
await createNewSocket(channelsToConnect); | ||
connectedChannelCount += channelsToConnect.length; | ||
} | ||
}; | ||
|
||
const client = async (channels: string[]) => { | ||
const chatroomIds = await getChatroomId(channels); | ||
connectToDynamicChannels(chatroomIds); | ||
}; | ||
|
||
client(["botk4cp3r"]); |
Oops, something went wrong.