switch to twurple

This commit is contained in:
Darius
2025-09-26 15:14:03 +02:00
parent 9a961363f3
commit 47a4103176
12 changed files with 345 additions and 103 deletions

View File

@@ -1,13 +1,5 @@
import type { Events } from "tmi.js";
import { client } from "./core/client.ts";
import { events } from "./events/collection.ts";
// Register all events with the TMI client
for (const [eventName, eventHandler] of events) {
client.on(
eventName as keyof Events,
eventHandler.triggered.bind(null, client),
);
}
import { registerAllEvents } from "./events/registry.ts";
registerAllEvents(client);
client.connect();

View File

@@ -1,4 +1,5 @@
import type { ChatUserstate, Client } from "tmi.js";
import type { ChatMessage } from "@twurple/chat";
import { logSuccess } from "../logger/logger.ts";
import type { ICommand, ICommandRequirements } from "./interface.ts";
export class SongCommand implements ICommand {
@@ -12,12 +13,12 @@ export class SongCommand implements ICommand {
};
triggered = async (
client: Client,
channel: string,
_state: ChatUserstate,
_message: string,
_args: Array<string>,
user: string,
text: string,
msg: ChatMessage,
) => {
client.say(channel, "testing");
logSuccess(`${channel} song command triggered`);
// client.say(channel, "testing");
};
}

View File

@@ -4,8 +4,9 @@ dotenv.config();
export const Config = {
prefix: process.env.PREFIX || "",
username: process.env.USERNAME || "",
access_token: process.env.ACCESS_TOKEN || "",
bot_user_id: process.env.BOT_USER_ID || "",
client_id: process.env.CLIENT_ID || "",
client_secret: process.env.CLIENT_SECRET || "",
channels: [process.env.CHANNELS || ""],
developers: [process.env.DEVELOPERS || ""],
};

View File

@@ -1,11 +1,30 @@
import { Client } from "tmi.js";
import { promises as fs } from "node:fs";
import { RefreshingAuthProvider } from "@twurple/auth";
import { ChatClient } from "@twurple/chat";
import { Config } from "../config/config.ts";
export const client = new Client({
connection: { reconnect: true, secure: true },
identity: {
username: Config.username,
password: `oauth:${Config.access_token}`,
},
// Auth Token Stuff
const tokenData = JSON.parse(
await fs.readFile("./tokens.125328655.json", "utf-8"),
);
const authProvider = new RefreshingAuthProvider({
clientId: Config.client_id,
clientSecret: Config.client_secret,
});
authProvider.onRefresh(
async (userId, newTokenData) =>
await fs.writeFile(
`./tokens.${userId}.json`,
JSON.stringify(newTokenData, null, 4),
"utf-8",
),
);
await authProvider.addUserForToken(tokenData, ["chat"]);
export const client = new ChatClient({
authProvider,
channels: Config.channels,
});

View File

@@ -1,9 +0,0 @@
import { Collection } from "@discordjs/collection";
import ConnectedEvent from "./event-connected.ts";
import MessageEvent from "./event-message.ts";
import type { IEvent } from "./interface.ts";
export const events = new Collection<string, IEvent>();
events.set(ConnectedEvent.name, new ConnectedEvent());
events.set(MessageEvent.name, new MessageEvent());

View File

@@ -1,11 +1,11 @@
import type { Events } from "tmi.js";
import { logSuccess } from "../logger/logger.ts";
import type { IEvent } from "./interface.ts";
import type { EventName } from "./registry.ts";
export default class ConnectedEvent implements IEvent {
name: keyof Events = "connected";
name: EventName = "connected";
triggered = async () => {
logSuccess("connected");
logSuccess(this.name);
};
}

View File

@@ -1,66 +1,63 @@
import { Collection } from "@discordjs/collection";
import type { ChatUserstate, Client, Events } from "tmi.js";
import type { ChatMessage } from "@twurple/chat";
import { commands } from "../commands/collection.ts";
import type { ICommand } from "../commands/interface.ts";
import { Config } from "../config/config.ts";
import type { IEvent } from "./interface.ts";
import type { EventName } from "./registry.ts";
const Cooldowns = new Collection<string, number>();
export default class MessageEvent implements IEvent {
name: keyof Events = "message";
name: EventName = "message";
triggered = async (
client: Client,
channel: string,
state: ChatUserstate,
message: string,
self: boolean,
user: string,
text: string,
msg: ChatMessage,
) => {
if (self) return;
await checkMessage(client, channel, state, message);
await checkMessage(channel, user, text, msg);
};
}
async function checkMessage(
client: Client,
channel: string,
state: ChatUserstate,
message: string,
user: string,
text: string,
msg: ChatMessage,
) {
const prefix = Config.prefix;
if (!text.startsWith(prefix)) return;
if (!message.startsWith(prefix)) return;
const args = message.slice(prefix.length).trim().split(/ +/g);
const commandName = args[0].toLowerCase();
const commandName = text
.slice(prefix.length)
.trim()
.split(/ +/g)[0]
.toLowerCase();
const command = commands.get(commandName);
if (!command) return;
if (!command.enabled) return;
const userId = state["user-id"] as string;
if (command.requirements.developer && !isDeveloper(userId)) return;
if (command.requirements.mod && !isMod(state)) return;
if (command.requirements.developer && !isDeveloper(msg.userInfo.userId))
return;
if (command.requirements.mod && !msg.userInfo.isMod) return;
const timeLeft = checkCooldown(command);
if (timeLeft > 0) {
return client.say(
channel,
`you must wait ${timeLeft} more seconds to use the command again`,
);
// return client.say(
// channel,
// `@${user}, you must wait ${timeLeft} more seconds to use the command again`,
// );
}
await command.triggered(client, channel, state, message, args);
await command.triggered(channel, user, text, msg);
}
function isDeveloper(userId: string): boolean {
return Config.developers.includes(userId);
}
function isMod(state: ChatUserstate): boolean {
return state.mod as boolean;
}
function checkCooldown(command: ICommand): number {
const now = Date.now();
if (command.cooldown > 0) {

View File

@@ -1,6 +1,6 @@
import type { Events } from "tmi.js";
import type { EventName } from "./registry";
export interface IEvent {
name: keyof Events;
name: EventName;
triggered(...args: unknown[]): Promise<unknown>;
}

24
src/events/registry.ts Normal file
View File

@@ -0,0 +1,24 @@
import type { ChatClient } from "@twurple/chat";
import ConnectedEvent from "./event-connected";
import MessageEvent from "./event-message";
import type { IEvent } from "./interface";
export const eventRegistry = {
message: (client: ChatClient, handler: IEvent) =>
client.onMessage(handler.triggered),
connected: (client: ChatClient, handler: IEvent) =>
client.onConnect(handler.triggered),
};
export function registerAllEvents(client: ChatClient) {
const events = [new MessageEvent(), new ConnectedEvent()];
for (const event of events) {
const registerFn = eventRegistry[event.name];
if (registerFn) {
registerFn(client, event);
}
}
}
export type EventName = keyof typeof eventRegistry;