From aa31e8f5a08541bead55154b1a63eabc7c472f5d Mon Sep 17 00:00:00 2001 From: DeSqBlocki Date: Sat, 21 Dec 2024 17:32:07 +0100 Subject: [PATCH] Made Clients available globally via exports and sanitized channel names --- commands/channels/channels.js | 68 +++++++++++------- index.js | 128 ++++------------------------------ 2 files changed, 54 insertions(+), 142 deletions(-) diff --git a/commands/channels/channels.js b/commands/channels/channels.js index 61f23b0..0733249 100644 --- a/commands/channels/channels.js +++ b/commands/channels/channels.js @@ -1,14 +1,11 @@ const { configDotenv } = require('dotenv'); -const { MongoClient } = require('mongodb'); -const TwitchApi = require("node-twitch").default -const tClient = new TwitchApi({ - client_id: process.env.TTV_ID, - client_secret: process.env.TTV_SECRET -}); configDotenv -const mClient = new MongoClient(process.env.MONGO_URL); const { SlashCommandBuilder, EmbedBuilder } = require('discord.js'); +const { tClient, mClient } = require('../../index'); +function escapeMarkdown(input){ + return input.replace(/([*_#\[!\]()`>+\-.|])/g, '\\$1'); +} async function SubscribeChannel(interaction) { const channelName = encodeURI(await interaction.options.getString('channel')).toLowerCase() const userID = interaction.user.id @@ -17,7 +14,7 @@ async function SubscribeChannel(interaction) { //console.log(await tClient.searchChannels({query: `${channelName}`})) // returns too many results and not exact match first } catch (error) { return interaction.reply({ - content: `**[ERROR]:** Could not validate channel name for *${channelName}*!\r\n${error}`, + content: `**[ERROR]:** Could not validate channel name for *${escapeMarkdown(channelName)}*!\r\n${error}`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() @@ -30,9 +27,9 @@ async function SubscribeChannel(interaction) { const find = await channelsColl.find({ channel: channelName }).toArray() if (find[0]) { - if (find[0].users.includes(userID)) { + if (find[0].subscribers.includes(userID)) { return interaction.reply({ - content: `**[WARNING]:** You are already subscribed to *${channelName}*!`, + content: `**[WARNING]:** You are already subscribed to *${escapeMarkdown(channelName)}*!`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() @@ -48,7 +45,7 @@ async function SubscribeChannel(interaction) { channel: channelName, }, $push: { - users: userID + subscribers: userID } }, { upsert: true, @@ -64,7 +61,7 @@ async function SubscribeChannel(interaction) { } //console.log(res) // debug return interaction.reply({ - content: `**[SUCCESS]:** You are now subscribed to *${channelName}*!`, + content: `**[SUCCESS]:** You are now subscribed to *${escapeMarkdown(channelName)}*!`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() @@ -81,9 +78,9 @@ async function UnsubscribeChannel(interaction) { const find = await channelsColl.find({ channel: channelName }).toArray() if (find[0]) { - if (!find[0].users.includes(userID)) { + if (!find[0].subscribers.includes(userID)) { return interaction.reply({ - content: `**[WARNING]:** You were not subscribed to *${channelName}*!`, + content: `**[WARNING]:** You were not subscribed to *${escapeMarkdown(channelName)}*!`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() @@ -99,12 +96,17 @@ async function UnsubscribeChannel(interaction) { channel: channelName, }, $pull: { - users: userID + subscribers: userID } }, { upsert: true, returnDocument: 'after' }) + if(!res.subscribers[0]){ + const newRes = await channelsColl.findOneAndDelete({ + channel: channelName + }) + } } catch (error) { return interaction.reply({ content: `**[ERROR]:** There was an issue with the database!\r\n${error}`, @@ -113,9 +115,11 @@ async function UnsubscribeChannel(interaction) { interaction.deleteReply() }, 5000)) } + + //console.log(res) // debug return interaction.reply({ - content: `**[SUCCESS]:** You are no longer subscribed to *${channelName}*!`, + content: `**[SUCCESS]:** You are no longer subscribed to *${escapeMarkdown(channelName)}*!`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() @@ -128,19 +132,29 @@ async function ListChannel(interaction) { const db = mClient.db('notifyme') const channelsColl = db.collection('channels') - const find = await channelsColl.find({ users: userID }).toArray() + const find = await channelsColl.find({ subscribers: userID }).toArray() + if (!find[0]) { + return interaction.reply({ + content: `You are not subscribed to any channels!`, + ephemeral: true + }).then(setTimeout(() => { + interaction.deleteReply() + }, 5000)) + } var channelList = [] find.forEach((document) => { - channelList.push(document.channel) + channelList.push(escapeMarkdown(document.channel)) }) const embed = new EmbedBuilder() - .setTitle('Lists of Subscribed Channels:') + .setTitle('List of Subscribed Channels:') .setDescription(channelList.join("\n")) return interaction.reply({ embeds: [embed], ephemeral: true - }) + }).then(setTimeout(() => { + interaction.deleteReply() + }, 60000)) } async function InfoChannel(interaction) { @@ -164,16 +178,18 @@ async function InfoChannel(interaction) { .setURL(`https://twitch.tv/${channelName}`) let footer = "" liveData.tags.forEach((tag) => { - footer += `${footer?',':''} #${tag}` + footer += `#${tag} ` + }) + embed.setFooter({ + text: footer }) - embed.setFooter({ - text: footer - }) return interaction.reply({ embeds: [embed], ephemeral: true - }) + }).then(setTimeout(() => { + interaction.deleteReply() + }, 60000)) } else { const embed = new EmbedBuilder() .setTitle(`${channelName} is currently offline!`) @@ -189,7 +205,7 @@ async function InfoChannel(interaction) { } catch (error) { console.error(error) return interaction.reply({ - content: `**[ERROR]:** Could not validate channel name for *${channelName}*!\r\n${error}`, + content: `**[ERROR]:** Could not validate channel name for *${escapeMarkdown(channelName)}*!\r\n${error}`, ephemeral: true }).then(setTimeout(() => { interaction.deleteReply() diff --git a/index.js b/index.js index 7270bc6..3f45d6b 100644 --- a/index.js +++ b/index.js @@ -14,126 +14,22 @@ const dClient = new Client({ Partials.Channel ] }); - dClient.commands = new Collection() // slash commands collection exports.dClient = dClient +const TwitchApi = require("node-twitch").default +const tClient = new TwitchApi({ + client_id: process.env.TTV_ID, + client_secret: process.env.TTV_SECRET +}); +exports.tClient = tClient + +const { MongoClient } = require('mongodb'); +const mClient = new MongoClient(process.env.MONGO_URL); +exports.mClient = mClient + fs.readdirSync('./handlers').forEach((handler) => { require(`./handlers/${handler}`) }); -dClient.login(process.env.DISCORD_Token) - - -// async function getStreamdata(stream) { -// var streamData -// await TwitchClient.getStreams({ channel: stream }).then(async data => { -// const r = data.data[0] -// if (r) { -// //stream online -// if (!isLive.has(stream)) { -// //not yet in memory -// streamData = { -// "game": r.game_name, -// "title": r.title, -// } -// isLive.add(stream) -// } else { -// //already in memory -// } -// } else { -// //stream offline -// if (isLive.has(stream)) { -// //was in memory -// console.log(`${stream} went offline :c`) -// isLive.delete(stream) -// } else { -// //was not in memory -// } -// } -// }) -// return streamData -// } - -// async function doInterval() { -// const guild = client.guilds.fetch('848610258306072576') -// for (const [key, value] of Object.entries(channels)) { -// //key: channel, value: [ users ] -// let streamdata = await getStreamdata(key) -// if(streamdata){ -// value.forEach(async userID =>{ -// (await guild).members.fetch(userID) -// .then((u => { -// u.send(`https://twitch.tv/${key} is live!`) -// console.log(`${key} is live!`) -// })) -// }) -// } -// } -// } -// client.once(Events.ClientReady, async client => { -// console.log(`Ready! Logged in as ${client.user.tag}`) -// doInterval() -// setInterval(async () => { -// doInterval() -// }, 2000) -// }); - -// client.on(Events.MessageCreate, async (msg) => { -// if (msg.author.bot) { return } -// console.log(msg.content) -// if (!msg.content.startsWith('!')) { return } - -// const args = msg.content.substring(1).split(' ') -// switch (args[0]) { -// case "add": -// addChannel(args[1], msg) -// break; -// case "remove": -// delChannel(args[1], msg) -// break; -// case "list": -// listChannels(msg) -// default: -// break; -// } -// }) - -// function addChannel(channel, msg) { -// if (!channels[channel]) { -// channels[channel] = [msg.author.id] -// } else { -// channels[channel].push(msg.author.id) -// } -// fs.writeFileSync('./channels.json', JSON.stringify(channels), 'utf-8') -// msg.reply({ -// content: `Subscribed to [${channel}] Notifications!` -// }) -// } -// function delChannel(channel, msg) { -// let index = channels[channel].indexOf(msg.author.id) -// channels[channel].splice(index) -// if (channels[channel].length === 0) { -// delete channels[channel] -// } -// fs.writeFileSync('./channels.json', JSON.stringify(channels), 'utf-8') -// msg.reply({ -// content: `Unsubscribed from [${channel}] Notifications!` -// }) -// } -// function listChannels(msg){ -// let subscribed = [] -// let embed = new EmbedBuilder() -// .setTitle('Lists of Subscribed Channels:') -// for (const [key, value] of Object.entries(channels)) { -// if(value.includes(msg.author.id)){ -// subscribed.push(key) -// } -// } -// embed.setDescription(subscribed.join("\n")) - -// msg.reply({ -// embeds: [embed] -// }) -// } -// client.login(process.env.DISCORD_Token); +dClient.login(process.env.DISCORD_Token) \ No newline at end of file