Compare commits

..

10 Commits

Author SHA1 Message Date
DeSqBlocki 0e996a349a Merge branch 'master' of https://github.com/DeSqBlocki/Hel-Bot 2025-02-15 17:10:02 +01:00
DeSqBlocki 84c9032891 added a message to the embed 2025-02-15 17:09:58 +01:00
DeSqBlocki c7727474c9 Update channel.js 2025-02-13 21:31:42 +01:00
DeSqBlocki 29f6c0cca1 updated README 2025-02-13 21:09:40 +01:00
DeSqBlocki 85f031c33a added settings 2025-02-13 21:04:53 +01:00
DeSqBlocki 5b07182020 separated commands from message event and added state control to them 2025-02-13 19:45:13 +01:00
DeSqBlocki fe0c937fb2 added error listener 2025-02-11 18:06:11 +01:00
DeSqBlocki dcea3ce294 silence res 2025-02-10 17:28:35 +01:00
DeSqBlocki 0ca35deb6e funky reconnect when losing internet 2025-02-10 17:27:53 +01:00
DeSqBlocki 96af757961 forgot to add functions 2025-02-10 17:10:37 +01:00
16 changed files with 456 additions and 160 deletions
+22 -11
View File
@@ -5,34 +5,45 @@ HelBot v5 introduces an improved background logic structure, streamlined integra
### Database Structure: ### Database Structure:
**client.credentials**: **client.credentials**:
- `_id` - `client_id` (twitch:discord)
- `client_id` - `client_secret` (twitch:discord)
- `client_secret` - `token` (access_token:token)
- `token` - `service` (twitch:discord)
- `service` - `mod_id` (twitch only)
- `mod_id`
**shoutouts.#channel**: **shoutouts.#channel**:
- `_id`
- `user` - `user`
- `created_at` - `created_at`
**guilds.id**: **guilds.id**:
- `_id` - `event`
- `settings` - `channel`
- `channels`
**commands.channel**:
- `name`
- `enabled`
**settings.channel**:
- `name`
- `enabled`
### Chat Commands: ### Chat Commands:
**Update Chat Mode** (Mods & Broadcaster only) **Update Chat Mode** (Mods & Broadcaster only)
- `$mode [on:off]` - `$mode [on:off]`
**Get a Random Positive Reminder** **Get A Positive Reminder**
- `$positivity` - `$positivity`
**View Donothon/Charity Event Information** **View Donothon/Charity Event Information**
- `$donate` - `$donate`
**View / Manage Settings**
- `$commands [enable:disable] [setting]`
**View / Manage Commands**
- `$commands [enable:disable] [command]`
### Behaviour: ### Behaviour:
- Automatically protects the chat by enabling **follow-only**, **sub-only**, or **emote-only** modes when the stream goes offline. - Automatically protects the chat by enabling **follow-only**, **sub-only**, or **emote-only** modes when the stream goes offline.
+44
View File
@@ -54,6 +54,29 @@ async function getChannel(interaction) {
}, 5000)) }, 5000))
} }
} }
async function unsetChannel(interaction) {
const event = interaction.options.getString('event')
const db = mClient.db('guilds')
const coll = db.collection(interaction.guild.id)
try {
await coll.deleteOne({
event: event
})
return interaction.editReply({
content: `Channel for Event: ${event} has been unset`,
flags: MessageFlags.Ephemeral
})
} catch (error) {
return interaction.editReply({
content: `**[ERROR]:** ${event} is currently not set to any channel`,
flags: MessageFlags.Ephemeral
}).then(setTimeout(() => {
interaction.deleteReply()
}, 5000))
}
}
module.exports = { module.exports = {
data: new SlashCommandBuilder() data: new SlashCommandBuilder()
.setName('channel') .setName('channel')
@@ -100,6 +123,24 @@ module.exports = {
]) ])
.setRequired(true) .setRequired(true)
) )
)
.addSubcommand(s =>
s
.setName('unset')
.setDescription('unset channel for certain events')
.addStringOption(o =>
o
.setName('event')
.setDescription('choose the event')
.addChoices([
{ "name": "When a user joins this server", "value": "GuildMemberAdd" },
{ "name": "When a user left this server", "value": "GuildMemberRemove" },
{ "name": "When it's a users birthday", "value": "Discord/Birthday" },
{ "name": "When debug logs are sent", "value": "Discord/Logs" },
{ "name": "When stream is live", "value": "Twitch/Online" }
])
.setRequired(true)
)
), ),
async execute(interaction) { async execute(interaction) {
if (!interaction.member.permissions.has("ADMINISTRATOR")) { if (!interaction.member.permissions.has("ADMINISTRATOR")) {
@@ -116,6 +157,9 @@ module.exports = {
case "get": case "get":
getChannel(interaction) getChannel(interaction)
break; break;
case "unset":
unsetChannel(interaction)
break;
default: default:
break; break;
} }
+6 -16
View File
@@ -1,29 +1,19 @@
// Event triggered by client connected to server // Event triggered by client connected to server
const { RWSConnect, RWSDisconnect } = require("../../functions") const { mClient, dClient } = require("../..");
var { tClient } = require('../..')
const { refreshAccessToken } = require("../../functions")
const tmi = require('tmi.js')
module.exports = { module.exports = {
name: 'Twitch/Disconnected', name: 'Twitch/Disconnected',
once: false, once: false,
async execute(reason) { async execute(reason) {
console.log('Twitch disconnected:', reason); console.log('Twitch disconnected:', reason);
try {
RWSDisconnect()
} catch (error) {
console.error
}
if (reason.includes('Login authentication failed')) { if (reason.includes('Login authentication failed')) {
try { try {
await refreshAccessToken(); await refreshAccessToken();
console.log('Reinitializing Twitch client after token refresh...'); console.log('Reinitializing Twitch client after token refresh...');
try {
await tClient.disconnect();
} catch (err) {
console.warn('Twitch client already disconnected:', err.message);
}
const db = mClient.db("clients"); const db = mClient.db("clients");
const credentialCollection = db.collection('credentials'); const credentialCollection = db.collection('credentials');
const tCreds = await credentialCollection.findOne({ service: 'twitch' }); const tCreds = await credentialCollection.findOne({ service: 'twitch' });
@@ -38,8 +28,8 @@ module.exports = {
}, },
channels: tClient.channels, channels: tClient.channels,
}); });
const { address, port } = await tClient.connect()
await tClient.connect(); dClient.emit("Twitch/Connected", address, port)
console.log('Twitch client reconnected successfully.'); console.log('Twitch client reconnected successfully.');
} catch (error) { } catch (error) {
console.error('Failed to refresh token and reconnect:', error); console.error('Failed to refresh token and reconnect:', error);
+7 -1
View File
@@ -12,6 +12,7 @@ module.exports = {
name: 'Twitch/EventSub', name: 'Twitch/EventSub',
once: false, once: false,
async execute() { async execute() {
console.log('Starting Event Subs...')
const endpoint = `wss://eventsub.wss.twitch.tv/ws` const endpoint = `wss://eventsub.wss.twitch.tv/ws`
const db = mClient.db('clients') const db = mClient.db('clients')
@@ -39,6 +40,9 @@ module.exports = {
function onDisconnect(reason) { function onDisconnect(reason) {
console.log(`Disconnecting due to reason`, reason) console.log(`Disconnecting due to reason`, reason)
} }
function onError(error){
console.log(error)
}
function connect() { function connect() {
connection = new ReconnectingWebSocket(endpoint, [], { connection = new ReconnectingWebSocket(endpoint, [], {
WebSocket: WebSocket, WebSocket: WebSocket,
@@ -48,6 +52,7 @@ module.exports = {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
connection.onclose = ({ reason }) => onDisconnect(reason, reject) connection.onclose = ({ reason }) => onDisconnect(reason, reject)
connection.onmessage = ({ data }) => onMessage(data, resolve) connection.onmessage = ({ data }) => onMessage(data, resolve)
connection.onerror = ({ error }) => onError(error)
}) })
} }
function onMessage(data) { function onMessage(data) {
@@ -92,6 +97,7 @@ module.exports = {
subscribedEvents[type] = listener subscribedEvents[type] = listener
return true return true
} }
connect(options) connect(options)
if (options.debug) { if (options.debug) {
events.on(WebsocketEvents.CONNECTED, () => { events.on(WebsocketEvents.CONNECTED, () => {
@@ -105,7 +111,7 @@ module.exports = {
const conditions = [{ const conditions = [{
broadcaster_user_id: String(await getIDByName("x__hel__x")) broadcaster_user_id: String(await getIDByName("x__hel__x"))
},{ }, {
broadcaster_user_id: String(await getIDByName("desq_blocki")) broadcaster_user_id: String(await getIDByName("desq_blocki"))
}] }]
+12 -48
View File
@@ -21,48 +21,6 @@ module.exports = {
}) })
} }
} }
async function sendPositivity() {
// Function sends a random string of predetermined positivity, Donothon Top Donator Reward
let positive_Messages = [
"You are so very worthy of all the love and support that may come your way.",
"There are many things which draw us together. In this time and place, that lovely subject is you, Hel.",
"The happiness and joy you add to the world is worth more than most anything.",
"You deserve every warm laugh, bright smile, and all the genuine kindness given to you.",
"There are few things as precious as your time. Thank you for sharing with us.",
"Your feelings are valid and you are not less than for having them.",
"I've seen all the work you do and I'm so very proud of you.",
"You are dearly cherished and I want to thank you for being so wonderfully you.",
"You. Are. Worthy. Enough. And I will tell you as many times as it takes for you to believe it.",
"Every day you give your best and that is so admirable. Don't let anyone tell you otherwise.",
"Your light is like that of the full moon, brightening our lives even in our darkest moments.",
"It's okay to take a moment to catch your breath. Even machines require maintenance from time to time.",
"Watching you succeed and achieve your heart's desires gives me so much motivation and I am very grateful for it."
]
let rdm = Math.floor(Math.random() * positive_Messages.length)
return tClient.say(channel, positive_Messages[rdm])
}
async function sendDonationAd() {
// Function to send static donate ad
const links = [
"https://bit.ly/heltwittergoals",
"https://bit.ly/donatetohel",
"http://bit.ly/donothon_goals"
];
const messages = [
"Hel is currently celebrating her birthday with a donathon!",
`You can see goals and incentives here: ${links[0]}`,
`You can donate here: ${links[1]}`,
`Terms, conditions, rules and how rewards work are found here: ${links[2]}`,
"All donations and gifts are greatly appreciated, but please do so responsibly!"
];
for (const message of messages) {
await tClient.say(channel, message);
}
}
if (self) { return } if (self) { return }
if (knownBots.has(userstate.username)) { return } if (knownBots.has(userstate.username)) { return }
@@ -87,16 +45,22 @@ module.exports = {
const cmd = args[0] const cmd = args[0]
switch (cmd) { switch (cmd) {
case "mode": case "mode":
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { break } // return stops all further operations, so you should just break out of switch dClient.emit('Command/mode', channel, userstate, message, self, args[1])
let regex = /^(on|off)$/
if (!args[1].match(regex)) { break }
updateChatMode(await getIDByName(channel.substring(1)), args[1])
break; break;
case "donate": case "donate":
sendDonationAd() dClient.emit('Command/donate', channel, userstate, message, self)
break; break;
case "positivity": case "positivity":
sendPositivity() dClient.emit('Command/positivity', channel, userstate, message, self)
break;
case "commands":
dClient.emit('Command/commands', channel, userstate, message, self, args[1], args[2])
break;
case "settings":
dClient.emit('Command/settings', channel, userstate, message, self, args[1], args[2])
break;
case "so":
dClient.emit('Command/so', channel, userstate, message, self, args[1])
break; break;
default: default:
break; break;
+31 -44
View File
@@ -7,15 +7,15 @@ module.exports = {
once: false, once: false,
async execute(stream) { async execute(stream) {
const db = mClient.db('guilds') const db = mClient.db('guilds')
const res = await db.listCollections().toArray() const guilds = await db.listCollections().toArray()
const streamer = stream.broadcaster_user_login const streamer = stream.broadcaster_user_login
console.log(`${streamer} went live!`) console.log(`${streamer} went live!`)
res.forEach(async (guildColl) => { guilds.forEach(async (guildData) => {
const guildId = guildColl.name const guildId = guildData.name
const coll = db.collection(guildId) const coll = db.collection(guildId)
const res = await coll.findOne({ event: 'Twitch/Online' }) const res = await coll.findOne({ event: 'Twitch/Online' })
if(!res){ if (!res) {
return // ignore if no live channel set return // ignore if no live channel set
} }
const guild = dClient.guilds.cache.get(guildId) const guild = dClient.guilds.cache.get(guildId)
@@ -23,47 +23,34 @@ module.exports = {
try { try {
const streamData = await getStreams(streamer) const streamData = await getStreams(streamer)
let liveData = {
if (streamData?.data[0]) { streamer: streamData.data[0].user_name,
let liveData = { game: streamData.data[0].game_name,
streamer: streamData.data[0].user_name, title: streamData.data[0].title,
game: streamData.data[0].game_name, thumbnail: streamData.data[0].thumbnail_url.replace('-{width}x{height}', ''),
title: streamData.data[0].title, tags: streamData.data[0].tags
thumbnail: streamData.data[0].thumbnail_url.replace('-{width}x{height}', ''),
tags: streamData.data[0].tags
}
const embed = new EmbedBuilder()
.setTitle(`${escapeMarkdown(liveData.streamer)} is live!`)
.setDescription(`They're playing ${liveData.game}`)
.addFields(
{ name: '\u200B', value: `${liveData.title}` })
.setImage(liveData.thumbnail)
.setURL(`https://twitch.tv/${streamer}`)
let footer = ""
liveData.tags.forEach((tag) => {
footer += `#${tag} `
})
embed.setFooter({
text: footer
})
return channel.send({
embeds: [embed],
flags: MessageFlags.Ephemeral
}).then(message => setTimeout(() => {
message.deleteReply()
}, 60000))
} else {
const embed = new EmbedBuilder()
.setTitle(`${escapeMarkdown(streamer)} is currently offline!`)
.setImage('https://media.discordapp.net/attachments/1061304429724319794/1319800268770250883/no-signal-tv-descendant-network-rainbow-bars-abstract-background-vector.jpg?ex=67674748&is=6765f5c8&hm=d539944a67fccec461b0183a9f0300e19ac485deda7b23090165088567f2c84f&=&format=webp')
.setURL(`https://twitch.tv/${streamer}`)
return channel.send({
embeds: [embed],
flags: MessageFlags.Ephemeral
})
} }
const embed = new EmbedBuilder()
.setTitle(`${escapeMarkdown(liveData.streamer)} is live!`)
.setDescription(`They're playing ${liveData.game}`)
.addFields(
{ name: '\u200B', value: `${liveData.title}` })
.setImage(liveData.thumbnail)
.setURL(`https://twitch.tv/${streamer}`)
let footer = ""
liveData.tags.forEach((tag) => {
footer += `#${tag} `
})
embed.setFooter({
text: footer
})
return channel.send({
content: `@everyone ${escapeMarkdown(streamer)} is live`,
embeds: [embed]
})
} catch (error) { } catch (error) {
return console.error return console.error
} }
+15 -1
View File
@@ -1,4 +1,4 @@
const { tClient } = require("../.."); const { tClient, mClient } = require("../..");
const { getChannelInformation } = require("../../functions"); const { getChannelInformation } = require("../../functions");
// Event triggered by Custom Shoutout emitted in Messages.js // Event triggered by Custom Shoutout emitted in Messages.js
@@ -9,6 +9,20 @@ module.exports = {
name: 'Twitch/Shoutout', name: 'Twitch/Shoutout',
once: false, once: false,
async execute(reason, channel, username) { async execute(reason, channel, username) {
// Check if shoutout is enabled
const db = mClient.db('settings')
const coll = db.collection(channel)
const setting = await coll.findOne({ name: 'shoutout' })
// create in disabled state if not exists
if (!setting) {
await coll.insertOne({
name: 'shoutout',
enabled: false // default
})
}
if (!setting?.enabled && reason != 'command' ){ return }
// Function to perform shoutout (Nightbot or custom) // Function to perform shoutout (Nightbot or custom)
async function doShoutouts(channel, user) { async function doShoutouts(channel, user) {
+82
View File
@@ -0,0 +1,82 @@
const { mClient, tClient } = require("../..");
module.exports = {
name: 'Command/commands',
once: false,
async execute(channel, userstate, message, self, state, name) {
const db = mClient.db('commands')
const coll = db.collection(channel)
const defaultCommands = await coll.find({ default: true}).toArray()
var isDefault = false
defaultCommands.forEach((command) => {
if(command.default && command.name == name ){
isDefault = true
}
})
if (isDefault){
return tClient.say(channel, `${name} can't be modified`)
}
const command = await coll.findOne({ name: 'commands' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'commands',
enabled: true,
default: true
})
}
// Default non-admin mode, give list of all enabled commands
if (!name) {
const commands = await coll.find({}).toArray()
var commandList = []
commands.forEach((command) => {
if(userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1){
commandList.push(` ${command.name}`)
} else {
commandList.push(` ${command.name}(${command.enabled?'✅':'❌'})`)
}
})
if (commandList.length == 0) {
return await tClient.say(channel, `No commands available in this channel`)
}
return await tClient.say(channel, `Command List: ${commandList.toString()}`)
}
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
if (!state) { return }
// Admin Mode & Additional Parameters were given
// Parameters are valid
switch (state) {
case 'enable':
state = true
break;
case 'disable':
state = false
break;
default:
return tClient.say(channel, `invalid state, expecting 'enable' or 'disable'`)
}
// command is valid
const findCommand = await coll.findOne({ name: name })
if (!findCommand) { return await tClient.say(channel, `Command [${name}] not found. Try using it first if it exists`) }
await coll.findOneAndUpdate({
name: name
}, {
$set: { enabled: state }
}, {
upsert: true
})
return await tClient.say(channel, `[${name}] has been set to [${state}]`)
}
}
+44
View File
@@ -0,0 +1,44 @@
const { mClient, tClient } = require("../..");
module.exports = {
name: 'Command/donate',
once: false,
async execute(channel, userstate, message, self) {
const db = mClient.db('commands')
const coll = db.collection(channel)
const command = await coll.findOne({ name: 'donate' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'donate',
enabled: false // default
})
}
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `)}
async function sendDonationAd() {
// Function to send static donate ad
const links = [
"https://bit.ly/heltwittergoals",
"https://bit.ly/donatetohel",
"http://bit.ly/donothon_goals"
];
const messages = [
"Hel is currently celebrating her birthday with a donathon!",
`You can see goals and incentives here: ${links[0]}`,
`You can donate here: ${links[1]}`,
`Terms, conditions, rules and how rewards work are found here: ${links[2]}`,
"All donations and gifts are greatly appreciated, but please do so responsibly!"
];
for (const message of messages) {
await tClient.say(channel, message);
}
}
sendDonationAd()
}
}
+25
View File
@@ -0,0 +1,25 @@
const { mClient, tClient } = require('../..')
const { updateChatMode, getIDByName } = require('../../functions')
module.exports = {
name: 'Command/mode',
once: false,
async execute(channel, userstate, message, self, params) {
const db = mClient.db('commands')
const coll = db.collection(channel)
const command = await coll.findOne({ name: 'mode' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'mode',
enabled: false // default
})
}
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `) }
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
let regex = /^(on|off)$/
if (!params.match(regex)) { return }
updateChatMode(await getIDByName(channel.substring(1)), params)
}
}
+43
View File
@@ -0,0 +1,43 @@
const { tClient, mClient } = require('../..')
module.exports = {
name: 'Command/positivity',
once: false,
async execute(channel, userstate, message, self) {
const db = mClient.db('commands')
const coll = db.collection(channel)
const command = await coll.findOne({ name: 'positivity' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'positivity',
enabled: false // default
})
}
if (!command?.enabled){ return tClient.say(channel, `This command is currently disabled `) }
async function sendPositivity() {
// Function sends a random string of predetermined positivity, Donothon Top Donator Reward
let positive_Messages = [
"You are so very worthy of all the love and support that may come your way.",
"There are many things which draw us together. In this time and place, that lovely subject is you, Hel.",
"The happiness and joy you add to the world is worth more than most anything.",
"You deserve every warm laugh, bright smile, and all the genuine kindness given to you.",
"There are few things as precious as your time. Thank you for sharing with us.",
"Your feelings are valid and you are not less than for having them.",
"I've seen all the work you do and I'm so very proud of you.",
"You are dearly cherished and I want to thank you for being so wonderfully you.",
"You. Are. Worthy. Enough. And I will tell you as many times as it takes for you to believe it.",
"Every day you give your best and that is so admirable. Don't let anyone tell you otherwise.",
"Your light is like that of the full moon, brightening our lives even in our darkest moments.",
"It's okay to take a moment to catch your breath. Even machines require maintenance from time to time.",
"Watching you succeed and achieve your heart's desires gives me so much motivation and I am very grateful for it."
]
let rdm = Math.floor(Math.random() * positive_Messages.length)
return tClient.say(channel, positive_Messages[rdm])
}
sendPositivity()
}
}
+69
View File
@@ -0,0 +1,69 @@
const { mClient, tClient } = require("../..");
module.exports = {
name: 'Command/settings',
once: false,
async execute(channel, userstate, message, self, state, name) {
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
const db = mClient.db('commands')
const coll = db.collection(channel)
const command = await coll.findOne({ name: 'settings' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'settings',
enabled: true,
default: true
})
}
if (!command?.enabled) { return tClient.say(channel, `This command is currently disabled `) }
const db2 = mClient.db('settings')
const coll2 = db2.collection(channel)
// Default non-admin mode, give list of all enabled commands
if (!name) {
const settings = await coll2.find({}).toArray()
var settingsList = []
console.log(settings)
settings.forEach((setting) => {
settingsList.push(` ${setting.name}(${setting.enabled?'✅':'❌'})`)
})
if (settingsList.length == 0) {
return await tClient.say(channel, `No settings available in this channel`)
}
return await tClient.say(channel, `Settings List: ${settingsList.toString()}`)
}
if (!state) { return }
// Parameters are valid
switch (state) {
case 'enable':
state = true
break;
case 'disable':
state = false
break;
default:
return tClient.say(channel, `invalid state, expecting 'enable' or 'disable'`)
}
// command is valid
const findSetting = await coll2.findOne({ name: name })
if (!findSetting) { return await tClient.say(channel, `Setting [${name}] not found.`) }
await coll2.findOneAndUpdate({
name: name
}, {
$set: { enabled: state }
}, {
upsert: true
})
return await tClient.say(channel, `[${name}] has been set to [${state}]`)
}
}
+23
View File
@@ -0,0 +1,23 @@
const { mClient, dClient, tClient } = require('../..')
const { updateChatMode, getIDByName } = require('../../functions')
module.exports = {
name: 'Command/so',
once: false,
async execute(channel, userstate, message, self, name) {
if (userstate.badges.moderator != 1 && userstate.badges.broadcaster != 1) { return }
const db = mClient.db('commands')
const coll = db.collection(channel)
const command = await coll.findOne({ name: 'so' })
// create in disabled state if not exists
if (!command) {
await coll.insertOne({
name: 'so',
enabled: false // default
})
}
if (!command?.enabled) { return tClient.say(channel, `This command is currently disabled `) }
dClient.emit('Twitch/Shoutout', 'command', channel, name)
}
}
-3
View File
@@ -1,8 +1,5 @@
const axios = require("axios"); const axios = require("axios");
const { mClient } = require("."); const { mClient } = require(".");
const ReconnectingWebSocket = require("reconnecting-websocket");
const { WebSocket } = require("ws");
const twitchEventSubWsUrl = 'wss://eventsub.wss.twitch.tv/ws';
// Delay function for pauses // Delay function for pauses
function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function delay(ms) { return new Promise(resolve => setTimeout(resolve, ms)); }
+1 -4
View File
@@ -1,9 +1,6 @@
const fs = require('node:fs') const fs = require('node:fs')
const path = require('node:path'); const path = require('node:path');
var { dClient, mClient, tClient } = require('..'); var { dClient, tClient } = require('..');
const { refreshAccessToken } = require('../functions');
const tmi = require('tmi.js')
const folderPath = path.join(__dirname, '../events') const folderPath = path.join(__dirname, '../events')
const eventFolders = fs.readdirSync(folderPath) const eventFolders = fs.readdirSync(folderPath)
+31 -31
View File
@@ -21,15 +21,15 @@
} }
}, },
"node_modules/@discordjs/builders": { "node_modules/@discordjs/builders": {
"version": "1.10.0", "version": "1.10.1",
"resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.0.tgz", "resolved": "https://registry.npmjs.org/@discordjs/builders/-/builders-1.10.1.tgz",
"integrity": "sha512-ikVZsZP+3shmVJ5S1oM+7SveUCK3L9fTyfA8aJ7uD9cNQlTqF+3Irbk2Y22KXTb3C3RNUahRkSInClJMkHrINg==", "integrity": "sha512-OWo1fY4ztL1/M/DUyRPShB4d/EzVfuUvPTRRHRIt/YxBrUYSz0a+JicD5F5zHFoNs2oTuWavxCOVFV1UljHTng==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@discordjs/formatters": "^0.6.0", "@discordjs/formatters": "^0.6.0",
"@discordjs/util": "^1.1.1", "@discordjs/util": "^1.1.1",
"@sapphire/shapeshift": "^4.0.0", "@sapphire/shapeshift": "^4.0.0",
"discord-api-types": "^0.37.114", "discord-api-types": "^0.37.119",
"fast-deep-equal": "^3.1.3", "fast-deep-equal": "^3.1.3",
"ts-mixer": "^6.0.4", "ts-mixer": "^6.0.4",
"tslib": "^2.6.3" "tslib": "^2.6.3"
@@ -66,9 +66,9 @@
} }
}, },
"node_modules/@discordjs/rest": { "node_modules/@discordjs/rest": {
"version": "2.4.2", "version": "2.4.3",
"resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.2.tgz", "resolved": "https://registry.npmjs.org/@discordjs/rest/-/rest-2.4.3.tgz",
"integrity": "sha512-9bOvXYLQd5IBg/kKGuEFq3cstVxAMJ6wMxO2U3wjrgO+lHv8oNCT+BBRpuzVQh7BoXKvk/gpajceGvQUiRoJ8g==", "integrity": "sha512-+SO4RKvWsM+y8uFHgYQrcTl/3+cY02uQOH7/7bKbVZsTfrfpoE62o5p+mmV+s7FVhTX82/kQUGGbu4YlV60RtA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@discordjs/collection": "^2.1.1", "@discordjs/collection": "^2.1.1",
@@ -76,10 +76,10 @@
"@sapphire/async-queue": "^1.5.3", "@sapphire/async-queue": "^1.5.3",
"@sapphire/snowflake": "^3.5.3", "@sapphire/snowflake": "^3.5.3",
"@vladfrangu/async_event_emitter": "^2.4.6", "@vladfrangu/async_event_emitter": "^2.4.6",
"discord-api-types": "^0.37.114", "discord-api-types": "^0.37.119",
"magic-bytes.js": "^1.10.0", "magic-bytes.js": "^1.10.0",
"tslib": "^2.6.3", "tslib": "^2.6.3",
"undici": "6.19.8" "undici": "6.21.1"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -113,18 +113,18 @@
} }
}, },
"node_modules/@discordjs/ws": { "node_modules/@discordjs/ws": {
"version": "1.2.0", "version": "1.2.1",
"resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.0.tgz", "resolved": "https://registry.npmjs.org/@discordjs/ws/-/ws-1.2.1.tgz",
"integrity": "sha512-QH5CAFe3wHDiedbO+EI3OOiyipwWd+Q6BdoFZUw/Wf2fw5Cv2fgU/9UEtJRmJa9RecI+TAhdGPadMaEIur5yJg==", "integrity": "sha512-PBvenhZG56a6tMWF/f4P6f4GxZKJTBG95n7aiGSPTnodmz4N5g60t79rSIAq7ywMbv8A4jFtexMruH+oe51aQQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@discordjs/collection": "^2.1.0", "@discordjs/collection": "^2.1.0",
"@discordjs/rest": "^2.4.1", "@discordjs/rest": "^2.4.3",
"@discordjs/util": "^1.1.0", "@discordjs/util": "^1.1.0",
"@sapphire/async-queue": "^1.5.2", "@sapphire/async-queue": "^1.5.2",
"@types/ws": "^8.5.10", "@types/ws": "^8.5.10",
"@vladfrangu/async_event_emitter": "^2.2.4", "@vladfrangu/async_event_emitter": "^2.2.4",
"discord-api-types": "^0.37.114", "discord-api-types": "^0.37.119",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"ws": "^8.17.0" "ws": "^8.17.0"
}, },
@@ -148,9 +148,9 @@
} }
}, },
"node_modules/@mongodb-js/saslprep": { "node_modules/@mongodb-js/saslprep": {
"version": "1.1.9", "version": "1.2.0",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.1.9.tgz", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.0.tgz",
"integrity": "sha512-tVkljjeEaAhCqTzajSdgbQ6gE6f3oneVwa3iXR6csiEwXXOFsiC6Uh9iAjAhXPtqa/XMDHWjjeNH/77m/Yq2dw==", "integrity": "sha512-+ywrb0AqkfaYuhHs6LxKWgqbh3I72EpEgESCw37o+9qPx9WTCkgDm2B+eMrwehGtHBWHFU4GXvnSCNiFhhausg==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"sparse-bitfield": "^3.0.3" "sparse-bitfield": "^3.0.3"
@@ -494,23 +494,23 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/discord.js": { "node_modules/discord.js": {
"version": "14.17.3", "version": "14.18.0",
"resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.17.3.tgz", "resolved": "https://registry.npmjs.org/discord.js/-/discord.js-14.18.0.tgz",
"integrity": "sha512-8/j8udc3CU7dz3Eqch64UaSHoJtUT6IXK4da5ixjbav4NAXJicloWswD/iwn1ImZEMoAV3LscsdO0zhBh6H+0Q==", "integrity": "sha512-SvU5kVUvwunQhN2/+0t55QW/1EHfB1lp0TtLZUSXVHDmyHTrdOj5LRKdR0zLcybaA15F+NtdWuWmGOX9lE+CAw==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"@discordjs/builders": "^1.10.0", "@discordjs/builders": "^1.10.1",
"@discordjs/collection": "1.5.3", "@discordjs/collection": "1.5.3",
"@discordjs/formatters": "^0.6.0", "@discordjs/formatters": "^0.6.0",
"@discordjs/rest": "^2.4.2", "@discordjs/rest": "^2.4.3",
"@discordjs/util": "^1.1.1", "@discordjs/util": "^1.1.1",
"@discordjs/ws": "^1.2.0", "@discordjs/ws": "^1.2.1",
"@sapphire/snowflake": "3.5.3", "@sapphire/snowflake": "3.5.3",
"discord-api-types": "^0.37.114", "discord-api-types": "^0.37.119",
"fast-deep-equal": "3.1.3", "fast-deep-equal": "3.1.3",
"lodash.snakecase": "4.1.1", "lodash.snakecase": "4.1.1",
"tslib": "^2.6.3", "tslib": "^2.6.3",
"undici": "6.19.8" "undici": "6.21.1"
}, },
"engines": { "engines": {
"node": ">=18" "node": ">=18"
@@ -1335,9 +1335,9 @@
"license": "MIT" "license": "MIT"
}, },
"node_modules/undici": { "node_modules/undici": {
"version": "6.19.8", "version": "6.21.1",
"resolved": "https://registry.npmjs.org/undici/-/undici-6.19.8.tgz", "resolved": "https://registry.npmjs.org/undici/-/undici-6.21.1.tgz",
"integrity": "sha512-U8uCCl2x9TK3WANvmBavymRzxbfFYG+tAu+fgx3zxQy3qdagQqBLwJVrdyO1TBfUXvfKveMKJZhpvUYoOjM+4g==", "integrity": "sha512-q/1rj5D0/zayJB2FraXdaWxbhWiNKDvu8naDT2dl1yTlvJp4BLtOcp2a5BvgGNQpYYJzau7tf1WgKv3b+7mqpQ==",
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=18.17" "node": ">=18.17"
@@ -1365,9 +1365,9 @@
} }
}, },
"node_modules/whatwg-url": { "node_modules/whatwg-url": {
"version": "14.1.0", "version": "14.1.1",
"resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.0.tgz", "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-14.1.1.tgz",
"integrity": "sha512-jlf/foYIKywAt3x/XWKZ/3rz8OSJPiWktjmk891alJUEjiVxKX9LEO92qH3hv4aJ0mN3MWPvGMCy8jQi95xK4w==", "integrity": "sha512-mDGf9diDad/giZ/Sm9Xi2YcyzaFpbdLpJPr+E9fSkyQ7KpQD4SdFcugkRQYzhmfI4KeV4Qpnn2sKPdo+kmsgRQ==",
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"tr46": "^5.0.0", "tr46": "^5.0.0",