From dbfb4f5d86bca05e62bd01d28b0bca3b4bb5d593 Mon Sep 17 00:00:00 2001 From: Darius Date: Mon, 29 Sep 2025 00:11:55 +0200 Subject: [PATCH] add ping command --- biome.json | 13 ++++++++++++ src/commands/base-command.ts | 18 +++++++++++++++- src/commands/collection.ts | 3 +++ src/commands/impl/ping.ts | 40 ++++++++++++++++++++++++++++++++++++ src/commands/impl/song.ts | 25 ++++------------------ src/events/impl/message.ts | 2 +- src/util/general.ts | 30 +++++++++++++++++++++++++++ 7 files changed, 108 insertions(+), 23 deletions(-) create mode 100644 biome.json create mode 100644 src/commands/impl/ping.ts diff --git a/biome.json b/biome.json new file mode 100644 index 0000000..25d3203 --- /dev/null +++ b/biome.json @@ -0,0 +1,13 @@ +{ + "linter": { + "rules": { + "correctness": { + "useImportExtensions": { + "options": { + "forceJsExtensions": true + } + } + } + } + } +} diff --git a/src/commands/base-command.ts b/src/commands/base-command.ts index fd30911..ffed26a 100644 --- a/src/commands/base-command.ts +++ b/src/commands/base-command.ts @@ -1,4 +1,5 @@ import type { ChatUser } from "@twurple/chat"; +import { Config } from "../config/config.ts"; import { chatClient } from "../core/chat-client.ts"; import type { ICommand, ICommandRequirements } from "./interface.ts"; @@ -10,7 +11,22 @@ export abstract class BaseCommand implements ICommand { abstract name: string; abstract cooldown: number; abstract enabled: boolean; - abstract checkPerms(user: ChatUser): boolean; abstract triggered(...args: unknown[]): Promise; abstract requirements: ICommandRequirements; + + checkPerms = (user: ChatUser): boolean => { + if (!this.enabled) { + return false; + } + + if ( + (this.requirements.developer && + !Config.developers.includes(user.userId)) || + (this.requirements.mod && !user.isMod) + ) { + return false; + } + + return true; + }; } diff --git a/src/commands/collection.ts b/src/commands/collection.ts index 9303ef3..504e665 100644 --- a/src/commands/collection.ts +++ b/src/commands/collection.ts @@ -1,9 +1,12 @@ import { Collection } from "@discordjs/collection"; +import { PingCommand } from "./impl/ping.ts"; import { SongCommand } from "./impl/song.ts"; import type { ICommand } from "./interface.ts"; export const commands = new Collection(); const songCommand = new SongCommand(); +const pingCommand = new PingCommand(); commands.set(songCommand.name, songCommand); +commands.set(pingCommand.name, pingCommand); diff --git a/src/commands/impl/ping.ts b/src/commands/impl/ping.ts new file mode 100644 index 0000000..d0d0239 --- /dev/null +++ b/src/commands/impl/ping.ts @@ -0,0 +1,40 @@ +import type { ChatMessage } from "@twurple/chat"; +import { calculateSecondsBetween } from "../../util/general.ts"; +import { logSuccess } from "../../util/logger.ts"; +import { BaseCommand } from "../base-command.ts"; +import type { ICommandRequirements } from "../interface.ts"; + +export class PingCommand extends BaseCommand { + started: number; + constructor() { + super(); + this.started = Date.now(); + } + + name = "ping"; + cooldown = 0; + enabled = true; + + requirements: ICommandRequirements = { + developer: false, + mod: false, + }; + + triggered = async ( + channel: string, + user: string, + _text: string, + msg: ChatMessage, + ) => { + logSuccess(`${channel} ${user} ping command triggered`); + const uptime = getUptime(this.started, Date.now()); + const message = `uptime: ${uptime}`; + this.chatClient.say(channel, message, { + replyTo: msg, + }); + }; +} + +function getUptime(start: number, now: number): string { + return calculateSecondsBetween(start, now).toReadable(); +} diff --git a/src/commands/impl/song.ts b/src/commands/impl/song.ts index c42c35d..8a89a67 100644 --- a/src/commands/impl/song.ts +++ b/src/commands/impl/song.ts @@ -1,7 +1,6 @@ -import type { ChatMessage, ChatUser } from "@twurple/chat"; +import type { ChatMessage } from "@twurple/chat"; import axios from "axios"; import { Config } from "../../config/config.ts"; -import { chatClient } from "../../core/chat-client.ts"; import { logSuccess, logWarning } from "../../util/logger.ts"; import { BaseCommand } from "../base-command.ts"; import type { ICommandRequirements } from "../interface.ts"; @@ -23,7 +22,7 @@ export class SongCommand extends BaseCommand { enabled = true; requirements: ICommandRequirements = { - developer: true, + developer: false, mod: false, }; @@ -37,27 +36,11 @@ export class SongCommand extends BaseCommand { const song = await getSongFromTidal(); if (song) { logSuccess(song); - chatClient.say(channel, song, { replyTo: msg }); + this.chatClient.say(channel, song, { replyTo: msg }); } else { - chatClient.say(channel, "tidal not running..", { replyTo: msg }); + this.chatClient.say(channel, "tidal not running..", { replyTo: msg }); } }; - - checkPerms = (user: ChatUser): boolean => { - if (!this.enabled) { - return false; - } - - if ( - (this.requirements.developer && - !Config.developers.includes(user.userId)) || - (this.requirements.mod && !user.isMod) - ) { - return false; - } - - return true; - }; } async function getSongFromTidal(): Promise { diff --git a/src/events/impl/message.ts b/src/events/impl/message.ts index e9c3f02..639ae85 100644 --- a/src/events/impl/message.ts +++ b/src/events/impl/message.ts @@ -40,7 +40,7 @@ async function checkMessage( // logInfo(`searching for command: ${commandName}`); const command = commands.get(commandName); if (!command) return; - if (!command.checkPerms) return; + if (!command.checkPerms(msg.userInfo)) return; const timeLeft = checkCooldown(command); if (timeLeft > 0) { diff --git a/src/util/general.ts b/src/util/general.ts index f1a15c6..4a527f8 100644 --- a/src/util/general.ts +++ b/src/util/general.ts @@ -25,3 +25,33 @@ export async function promptForInput(prompt: string): Promise { }); }); } + +export function calculateSecondsBetween( + start: number, + end: number, +): { seconds: number; toReadable: () => string } { + const seconds = (end - start) / 1000; + return { + seconds, + toReadable: () => secondsToReadable(seconds), + }; +} + +export function secondsToReadable(secs: number): string { + var days = Math.floor(secs / (3600 * 24)); + var hours = Math.floor((secs % (3600 * 24)) / 3600); + var minutes = Math.floor((secs % 3600) / 60); + var seconds = Math.floor(secs % 60); + + var dayDisplay = days > 0 ? days + (days === 1 ? " day, " : " days, ") : ""; + var hourDisplay = + hours > 0 ? hours + (hours === 1 ? " hour, " : " hours, ") : ""; + var minuteDisplay = + minutes > 0 ? minutes + (minutes === 1 ? " minute, " : " minutes, ") : ""; + var secondDisplay = + seconds > 0 ? seconds + (seconds === 1 ? " second" : " seconds") : ""; + return (dayDisplay + hourDisplay + minuteDisplay + secondDisplay).replace( + /,\s*$/, + "", + ); +}