diff --git a/events/ClientReady.js b/events/ClientReady.js index ba7dc2c..fca6d7e 100644 --- a/events/ClientReady.js +++ b/events/ClientReady.js @@ -1,17 +1,133 @@ -const { Events, ActivityType } = require('discord.js'); +const { Events, ActivityType, EmbedBuilder } = require('discord.js'); +const { mClient, tClient, dClient } = require('../index'); + +// Global Maps and Sets +const channelList = new Map(); // Stores channel names and their subscribers +const isLive = new Set(); // Stores channels that are live +const isOffline = new Set(); // Stores channels that are offline + module.exports = { name: Events.ClientReady, once: true, async execute(client) { - console.log(`Ready! Logged in as ${client.user.tag}`) + console.log(`Ready! Logged in as ${client.user.tag}`); + + // Set bot presence client.user.setPresence({ activities: [{ - name: 'Notyfing', + name: 'Notifications for you', type: ActivityType.Streaming, - url: 'https://twitch.tv/desq_blocki' + url: 'https://twitch.tv/desq_blocki', }], - status: 'online' - }) - + status: 'online', + }); + + // Main interval loop + setInterval(async () => { + await updateCache(); + await notifySubscribers(); + }, 5000); // Every 5 seconds + }, +}; + +// Update the cache from the database and clean up stale data +async function updateCache() { + const db = mClient.db('notifyme'); + const channelsColl = db.collection('channels'); + + try { + const channels = await channelsColl.find({}).toArray(); + const dbChannelNames = new Set(channels.map(channel => channel.name)); + + // Update channelList + channelList.clear(); + channels.forEach(channel => channelList.set(channel.name, channel.subscribers)); + + // Remove stale entries from isLive and isOffline + cleanUpSet(isLive, dbChannelNames); + cleanUpSet(isOffline, dbChannelNames); + + + // Debug + // console.log({ + // isLive: Array.from(isLive), + // isOffline: Array.from(isOffline), + // channels: Array.from(channelList.entries()), + // }); + + + } catch (error) { + console.error('Error updating cache:', error); } +} + +// Notify subscribers about live status changes +async function notifySubscribers() { + for (const [channelName, subscribers] of channelList) { + try { + const streamData = await tClient.getStreams({ channel: channelName }); + + if (streamData?.data[0]) { + // Stream is live + if (!isLive.has(channelName)) { + await notifyLive(channelName, subscribers, streamData.data[0]); + } + } else { + // Stream is offline + if (isLive.has(channelName)) { + console.log(`${channelName} went offline!`); + isLive.delete(channelName); + } + isOffline.add(channelName); + } + } catch (error) { + console.error(`Error notifying for ${channelName}:`, error); + } + } +} + +// Notify subscribers that a channel has gone live +async function notifyLive(channelName, subscribers, streamData) { + const liveData = { + streamer: streamData.user_name, + game: streamData.game_name, + title: streamData.title, + thumbnail: streamData.thumbnail_url.replace('-{width}x{height}', ''), + tags: streamData.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/${channelName}`) + .setFooter({ text: liveData.tags.map(tag => `#${tag}`).join(' ') }); + + for (const subscriber of subscribers) { + try { + const user = await dClient.users.fetch(subscriber); + await user.send({ embeds: [embed] }); + console.log(`${user.username} notified that ${channelName} went live!`); + } catch (error) { + console.error(`Error notifying ${subscriber}:`, error); + } + } + + isLive.add(channelName); + isOffline.delete(channelName); +} + +// Helper function to clean up stale data in a set +function cleanUpSet(set, validEntries) { + for (const entry of set) { + if (!validEntries.has(entry)) { + set.delete(entry); + } + } +} + +// Escape special markdown characters +function escapeMarkdown(input) { + return input.replace(/([*_#\[!\]()`>+\-.|])/g, '\\$1'); } \ No newline at end of file