import { Events, Client, ActivityType } from 'discord.js' import { SpotifyExtractor } from '@discord-player/extractor' import { YoutubeiExtractor } from 'discord-player-youtubei' import { useMainPlayer } from 'discord-player' import { connect } from 'mongoose' import WebSocket from 'websocket' import chalk from 'chalk' import 'dotenv/config' import dbGuildInit from '../../utils/dbGuildInit' import dbGuild from '../../schemas/guild' import { playerDisco, playerReplay } from '../../utils/player' import * as Twitch from '../../utils/twitch' import rss from '../../utils/rss' export default { name: Events.ClientReady, once: true, async execute(client: Client) { console.log(chalk.blue(`[DiscordJS] Connected to Discord ! Logged in as ${client.user?.tag ?? 'unknown'}`)) client.user?.setActivity('some bangers...', { type: ActivityType.Listening }) await useMainPlayer().extractors.register(SpotifyExtractor, {}).then(() => console.log(chalk.blue('[Discord-Player] Spotify extractor loaded.'))).catch(console.error) await useMainPlayer().extractors.register(YoutubeiExtractor, {}).then(() => console.log(chalk.blue('[Discord-Player] Youtube extractor loaded.'))).catch(console.error) let mongo_url = `mongodb://${process.env.MONGOOSE_USER}:${process.env.MONGOOSE_PASSWORD}@${process.env.MONGOOSE_HOST}/${process.env.MONGOOSE_DATABASE}` await connect(mongo_url).catch(console.error) let guilds = client.guilds.cache guilds.forEach(async guild => { let guildProfile = await dbGuild.findOne({ guildId: guild.id }) if (!guildProfile) guildProfile = await dbGuildInit(guild) if (guildProfile.guildPlayer?.replay?.enabled && guildProfile.guildPlayer?.replay?.textChannelId) await playerReplay(client, guildProfile) client.disco = { interval: {} as NodeJS.Timeout } client.disco.interval = setInterval(async () => { let guildProfile = await dbGuild.findOne({ guildId: guild.id }) if (guildProfile?.guildPlayer?.disco?.enabled) { let state = await playerDisco(client, guildProfile) if (state === 'clear') clearInterval(client.disco.interval) } }, 3000) client.rss = { interval: {} as NodeJS.Timeout } client.rss.interval = setInterval(async () => { let guildProfile = await dbGuild.findOne({ guildId: guild.id }) if (guildProfile?.guildRss?.enabled) { let state = await rss(client, guildProfile) if (state === 'clear') clearInterval(client.rss.interval) } }, 30000) // TWITCH EVENTSUB if (process.env['TWITCH_RUNNING_' + guild.id]) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Already running...`)) console.log(chalk.magenta(`[Twitch] {${guild.name}} Not running, starting...`)) process.env['TWITCH_RUNNING_' + guild.id] = 'true' let client_id = process.env.TWITCH_APP_ID as string let client_secret = process.env.TWITCH_APP_SECRET as string if (!client_id || !client_secret) return console.log(chalk.magenta(`[Twitch] {${guild.name}} App ID or Secret is not defined !`)) let dbData = guildProfile.get('guildTwitch') if (!dbData?.enabled) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Module is disabled, please activate with \`/database edit guildTwitch.enabled True\` !`)) let twitch = new WebSocket.client().on('connect', async connection => { console.log(chalk.magenta(`[Twitch] {${guild.name}} EventSub WebSocket Connected !`)) connection.on('message', async message => { if (message.type === 'utf8') { try { let data = JSON.parse(message.utf8Data) let channel_access_token = guildProfile.get('guildTwitch')?.channelAccessToken as string // Check when Twitch asks to login if (data.metadata.message_type === 'session_welcome') { // Check if the channel access token is still valid before connecting channel_access_token = await Twitch.checkChannel(client_id, client_secret, channel_access_token, guild) as string if (!channel_access_token) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Can't refresh channel access token !`)) // Get broadcaster user id and reward id let broadcaster_user_id = await Twitch.getUserInfo(client_id, channel_access_token, 'id') as string let topics: { [key: string]: { version: string; condition: { broadcaster_user_id: string } } } = { 'stream.online': { version: '1', condition: { broadcaster_user_id } }, 'stream.offline': { version: '1', condition: { broadcaster_user_id } } } // Subscribe to all events required for (let type in topics) { console.log(chalk.magenta(`[Twitch] {${guild.name}} Creating ${type}...`)) let { version, condition } = topics[type] let status = await Twitch.subscribeToEvents(client_id, channel_access_token, data.payload.session.id, type, version, condition) if (!status) return console.error(chalk.magenta(`[Twitch] {${guild.name}} Failed to create ${type}`)) else if (status.error) return console.log(chalk.magenta(`[Twitch] {${guild.name}} Erreur de connexion EventSub, veuillez vous reconnecter !`)) else console.log(chalk.magenta(`[Twitch] {${guild.name}} Successfully created ${type}`)) } } // Handle notification messages else if (data.metadata.message_type === 'notification') Twitch.notification(client_id, client_secret, channel_access_token, data, guild) } catch (error) { console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error)) } } }) .on('error', error => console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error))) .on('close', () => { console.log(chalk.magenta(`[Twitch] {${guild.name}} EventSub Connection Closed !`)) twitch.connect('wss://eventsub.wss.twitch.tv/ws') }) }).on('connectFailed', error => console.error(chalk.magenta(`[Twitch] {${guild.name}} ` + error))) twitch.connect('wss://eventsub.wss.twitch.tv/ws') }) } }